apti 0.6
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.
- checksums.yaml +7 -0
- data/AUTHORS +2 -0
- data/COPYING +674 -0
- data/README.md +42 -0
- data/TODO.md +7 -0
- data/bin/apti +70 -0
- data/changelog.xml +53 -0
- data/initial_config.yml +83 -0
- data/locales/en.yml +44 -0
- data/locales/fr.yml +44 -0
- data/src/apti/Apti.rb +791 -0
- data/src/apti/Package.rb +103 -0
- data/src/apti/config/Color.rb +223 -0
- data/src/apti/config/Colors.rb +85 -0
- data/src/apti/config/ColorsUpgrade.rb +65 -0
- data/src/apti/config/ColorsUpgradeRevision.rb +63 -0
- data/src/apti/config/ColorsUpgradeVersion.rb +64 -0
- data/src/apti/config/Config.rb +131 -0
- data/src/apti/config/Spaces.rb +85 -0
- data/src/apti/version.rb +6 -0
- metadata +78 -0
data/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Description
|
|
2
|
+
|
|
3
|
+
Apti is a frontend of aptitude (Debian's package manager) with improved presentation of packages.
|
|
4
|
+
|
|
5
|
+
It uses the same commands as aptitude, and allow you to use it without superuser rights (the sudo or root password is asked if needed).
|
|
6
|
+
|
|
7
|
+
The improved commands are: `install`, `remove`, `purge`, `safe-upgrade`, `full-upgrade` and `search`.
|
|
8
|
+
|
|
9
|
+
# Installation
|
|
10
|
+
|
|
11
|
+
Dependencies:
|
|
12
|
+
|
|
13
|
+
* aptitude (of course)
|
|
14
|
+
* ruby >= 1.9
|
|
15
|
+
* ruby-i18n
|
|
16
|
+
|
|
17
|
+
Put apti in /usr/local/, and create a link to main.rb: `ln -s /usr/local/apti/main.rb /usr/local/bin/apti`
|
|
18
|
+
|
|
19
|
+
Or with rubygems `gem build apti.gemspec` and then `gem install apti-0.5.1.gem`.
|
|
20
|
+
|
|
21
|
+
# Configuration
|
|
22
|
+
|
|
23
|
+
Configuration file is in ~/.config/apti (by default).
|
|
24
|
+
|
|
25
|
+
* colors:
|
|
26
|
+
* available colors are: BLACK, RED, GREEN, ORANGE, BLUE, MAGENTA, CYAN and WHITE.
|
|
27
|
+
* available effects are: NORMAL, BOLD, UNDERLINE, BLINK and HIGHLIGHT.
|
|
28
|
+
* display_size: displaying size of packages or not (default true).
|
|
29
|
+
* spaces:
|
|
30
|
+
* columns: between columns in `install`, `remove`, `upgrade`.
|
|
31
|
+
* unit: juste before size's unit.
|
|
32
|
+
* search: between package name and description.
|
|
33
|
+
* no_confirm: if true, don't ask for the aptitude's confirmation.
|
|
34
|
+
|
|
35
|
+
# Screenshots
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
|
data/TODO.md
ADDED
data/bin/apti
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
require_relative '../src/apti/Apti'
|
|
5
|
+
|
|
6
|
+
# Enable warnings.
|
|
7
|
+
$VERBOSE = true
|
|
8
|
+
|
|
9
|
+
apti = Apti::Apti.new
|
|
10
|
+
|
|
11
|
+
if ARGV[0].nil?
|
|
12
|
+
apti.help
|
|
13
|
+
exit(1)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
packages = ARGV[1..(ARGV.length - 1)].join(' ')
|
|
17
|
+
|
|
18
|
+
if ['search', 'remove', 'purge', 'install'].include?(ARGV[0]) && packages.empty?
|
|
19
|
+
apti.help
|
|
20
|
+
exit(1)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
case ARGV[0]
|
|
24
|
+
|
|
25
|
+
when '--help'
|
|
26
|
+
apti.help
|
|
27
|
+
when '-h'
|
|
28
|
+
apti.help
|
|
29
|
+
|
|
30
|
+
when '--version'
|
|
31
|
+
apti.version
|
|
32
|
+
|
|
33
|
+
when 'safe-upgrade'
|
|
34
|
+
apti.upgrade(packages)
|
|
35
|
+
|
|
36
|
+
when 'upgrade'
|
|
37
|
+
puts I18n.t(:'warning.upgrade')
|
|
38
|
+
apti.upgrade(packages)
|
|
39
|
+
|
|
40
|
+
when 'full-upgrade'
|
|
41
|
+
apti.upgrade(packages, true)
|
|
42
|
+
|
|
43
|
+
when 'search'
|
|
44
|
+
apti.search(packages)
|
|
45
|
+
|
|
46
|
+
when 'update'
|
|
47
|
+
apti.execute_command('aptitude update')
|
|
48
|
+
|
|
49
|
+
when 'remove'
|
|
50
|
+
apti.remove(packages)
|
|
51
|
+
|
|
52
|
+
when 'purge'
|
|
53
|
+
apti.remove(packages, true)
|
|
54
|
+
|
|
55
|
+
when 'install'
|
|
56
|
+
apti.install(packages)
|
|
57
|
+
|
|
58
|
+
when 'stats'
|
|
59
|
+
apti.stats
|
|
60
|
+
|
|
61
|
+
# other aptitude command
|
|
62
|
+
else
|
|
63
|
+
if ARGV[0].eql?(nil)
|
|
64
|
+
help
|
|
65
|
+
|
|
66
|
+
else
|
|
67
|
+
apti.execute_command "aptitude #{ARGV[0]} #{packages}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
data/changelog.xml
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<?xml-stylesheet type="text/xsl" href="changelog.xslt"?>
|
|
3
|
+
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
|
4
|
+
<channel>
|
|
5
|
+
<title>Apti's update log</title>
|
|
6
|
+
<link>https://gitorious.org/apti/apti</link>
|
|
7
|
+
<description>Log about all "stable" updates on Apti</description>
|
|
8
|
+
|
|
9
|
+
<atom:link href="https://gitorious.org/apti/apti/source/master:changelog.xml" rel="self" type="application/rss+xml" />
|
|
10
|
+
|
|
11
|
+
<lastBuildDate>Sun Mar 16 14:30:00 2014 +0100</lastBuildDate>
|
|
12
|
+
|
|
13
|
+
<item>
|
|
14
|
+
<title>Version 0.6</title>
|
|
15
|
+
<link>https://gitorious.org/apti/apti/source/v0.6:</link>
|
|
16
|
+
<guid isPermaLink="false">v0_6</guid>
|
|
17
|
+
<description><![CDATA[
|
|
18
|
+
<ul>
|
|
19
|
+
<li>Separate new revisions and new versions in upgrade.</li>
|
|
20
|
+
</ul>
|
|
21
|
+
]]></description>
|
|
22
|
+
<pubDate>Sun Mar 16 14:30:00 2014 +0100</pubDate>
|
|
23
|
+
</item>
|
|
24
|
+
|
|
25
|
+
<item>
|
|
26
|
+
<title>Version 0.5.1</title>
|
|
27
|
+
<link>https://gitorious.org/apti/apti/source/v0.5.1:</link>
|
|
28
|
+
<guid isPermaLink="false">v0_5_1</guid>
|
|
29
|
+
<description><![CDATA[
|
|
30
|
+
<ul>
|
|
31
|
+
<li>Fix bug when try to create the configuration directory of Apti ;</li>
|
|
32
|
+
<li>Fix problem in search when description is too long.</li>
|
|
33
|
+
</ul>
|
|
34
|
+
]]></description>
|
|
35
|
+
<pubDate>Tue Jan 28 13:32:47 2014 +0100</pubDate>
|
|
36
|
+
</item>
|
|
37
|
+
|
|
38
|
+
<item>
|
|
39
|
+
<title>Version 0.5</title>
|
|
40
|
+
<link>https://gitorious.org/apti/apti/source/v0.5:</link>
|
|
41
|
+
<guid isPermaLink="false">v0_5</guid>
|
|
42
|
+
<description><![CDATA[
|
|
43
|
+
<ul>
|
|
44
|
+
<li>Add internationalisation (English, French) ;</li>
|
|
45
|
+
<li>Better separations of packages (explicitly installed, dependencies, ...) ;</li>
|
|
46
|
+
<li>New configuration file (in yaml) with better personalisation (color, background, effect) ;</li>
|
|
47
|
+
<li>Some bug fixes.</li>
|
|
48
|
+
</ul>
|
|
49
|
+
]]></description>
|
|
50
|
+
<pubDate>Wed Jan 22 11:00:12 2014 +0100</pubDate>
|
|
51
|
+
</item>
|
|
52
|
+
</channel>
|
|
53
|
+
</rss>
|
data/initial_config.yml
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Generic configuration file for Apti
|
|
2
|
+
# Last modification : mar 13 2014
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
# Colors configuration
|
|
6
|
+
colors:
|
|
7
|
+
# Used when new package to install, Green / Bold if not present
|
|
8
|
+
install:
|
|
9
|
+
text: GREEN # Color of text
|
|
10
|
+
background: # Color of background
|
|
11
|
+
effect: BOLD # Some effect on text
|
|
12
|
+
|
|
13
|
+
# Used for upgrades
|
|
14
|
+
upgrade:
|
|
15
|
+
# Upgrades with revisions
|
|
16
|
+
revision:
|
|
17
|
+
# Color for common part of version, Orange / Bold if not present
|
|
18
|
+
static:
|
|
19
|
+
text: ORANGE
|
|
20
|
+
background:
|
|
21
|
+
effect: BOLD
|
|
22
|
+
|
|
23
|
+
# Color for old revision, Red / Bold if not present
|
|
24
|
+
old:
|
|
25
|
+
text: RED
|
|
26
|
+
background:
|
|
27
|
+
effect: BOLD
|
|
28
|
+
|
|
29
|
+
# Color for new revision, Green / Bold if not present
|
|
30
|
+
new:
|
|
31
|
+
text: GREEN
|
|
32
|
+
background:
|
|
33
|
+
effect: BOLD
|
|
34
|
+
|
|
35
|
+
# Upgrades with completely new version (no revision)
|
|
36
|
+
version:
|
|
37
|
+
# Color for old version, Red / Bold if not present
|
|
38
|
+
old:
|
|
39
|
+
text: RED
|
|
40
|
+
background:
|
|
41
|
+
effect: BOLD
|
|
42
|
+
|
|
43
|
+
# Color for new version, Green / Bold if not present
|
|
44
|
+
new:
|
|
45
|
+
text: GREEN
|
|
46
|
+
background:
|
|
47
|
+
effect: BOLD
|
|
48
|
+
|
|
49
|
+
# Color for removing / purging packages, Red / Bold if not present
|
|
50
|
+
remove:
|
|
51
|
+
text: RED
|
|
52
|
+
background:
|
|
53
|
+
effect: BOLD
|
|
54
|
+
|
|
55
|
+
# Color for descriptions (in search)
|
|
56
|
+
description:
|
|
57
|
+
text: BLACK
|
|
58
|
+
background:
|
|
59
|
+
effect: BOLD
|
|
60
|
+
|
|
61
|
+
# Color for packages size
|
|
62
|
+
size:
|
|
63
|
+
text: BLACK
|
|
64
|
+
background:
|
|
65
|
+
effect: BOLD
|
|
66
|
+
|
|
67
|
+
# Color for text, like "Upgrading, new revision:"
|
|
68
|
+
text:
|
|
69
|
+
text: WHITE
|
|
70
|
+
background:
|
|
71
|
+
effect: BOLD
|
|
72
|
+
|
|
73
|
+
# Apti must display size information?
|
|
74
|
+
display_size: true
|
|
75
|
+
|
|
76
|
+
# Spaces size
|
|
77
|
+
spaces:
|
|
78
|
+
columns: 3 # Spaces between two columns
|
|
79
|
+
unit: 1 # Spaces before size unit
|
|
80
|
+
search: 40 # Spaces in search alignment
|
|
81
|
+
|
|
82
|
+
# Must Apti ask to confirm operation (besides "aptitude" question)?
|
|
83
|
+
no_confirm: false
|
data/locales/en.yml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
en:
|
|
2
|
+
system_is_up_to_date: "System is up to date."
|
|
3
|
+
package_not_installed: "Package(s) not installed."
|
|
4
|
+
installing_for_dependencies: "Installing for dependencies:"
|
|
5
|
+
removing_unused_dependencies: "Removing unused dependencies:"
|
|
6
|
+
using: "Using:"
|
|
7
|
+
|
|
8
|
+
operation:
|
|
9
|
+
installing: "Installing:"
|
|
10
|
+
removing: "Removing:"
|
|
11
|
+
purging: "Purging:"
|
|
12
|
+
upgrading: "Upgrading,"
|
|
13
|
+
new_revisions: "new revisions:"
|
|
14
|
+
new_versions: "new versions:"
|
|
15
|
+
nothing_to_do: "Nothing to do."
|
|
16
|
+
question:
|
|
17
|
+
installation: "Continue the installation?"
|
|
18
|
+
remove: "Remove these package?"
|
|
19
|
+
purge: "Purge these packages?"
|
|
20
|
+
upgrade: "Continue the upgrade?"
|
|
21
|
+
|
|
22
|
+
error:
|
|
23
|
+
package:
|
|
24
|
+
not_found: "Couldn't find package(s): %{packages}"
|
|
25
|
+
installed: "Packages(s) already installed."
|
|
26
|
+
not_installed: "Packages(s) not installed."
|
|
27
|
+
|
|
28
|
+
header:
|
|
29
|
+
package: "Package"
|
|
30
|
+
version: "Version"
|
|
31
|
+
size: "Size"
|
|
32
|
+
|
|
33
|
+
stat:
|
|
34
|
+
total_installed: "Total installed packages: %{number}"
|
|
35
|
+
explicitly_installed : "Explicitly installed packages: %{number}"
|
|
36
|
+
space_used_in_cache: "Space used by packages in cache: %{size}"
|
|
37
|
+
|
|
38
|
+
warning:
|
|
39
|
+
upgrade: "Warning: upgrade is deprecated, use safe-upgrade."
|
|
40
|
+
|
|
41
|
+
number:
|
|
42
|
+
separator:
|
|
43
|
+
thousands: ","
|
|
44
|
+
decimal: "."
|
data/locales/fr.yml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
fr:
|
|
2
|
+
system_is_up_to_date: "Le système est à jour."
|
|
3
|
+
package_not_installed: "Paquet(s) non installé(s)."
|
|
4
|
+
installing_for_dependencies: "Installation pour dépendances :"
|
|
5
|
+
removing_unused_dependencies: "Suppression des dépendances non utilisées :"
|
|
6
|
+
using: "Utilisant :"
|
|
7
|
+
|
|
8
|
+
operation:
|
|
9
|
+
installing: "Installation :"
|
|
10
|
+
removing: "Suppression :"
|
|
11
|
+
purging: "Purge :"
|
|
12
|
+
upgrading: "Mise à jour,"
|
|
13
|
+
new_revisions: "nouvelles révisions :"
|
|
14
|
+
new_versions: "nouvelles versions :"
|
|
15
|
+
nothing_to_do: "Rien à faire."
|
|
16
|
+
question:
|
|
17
|
+
installation: "Continuer l'installation ?"
|
|
18
|
+
remove: "Supprimer ces paquets ?"
|
|
19
|
+
purge: "Purger ces paquets ?"
|
|
20
|
+
upgrade: "Continuer la mise à jour ?"
|
|
21
|
+
|
|
22
|
+
error:
|
|
23
|
+
package:
|
|
24
|
+
not_found: "Impossible de trouver le(s) paquet(s) : %{packages}"
|
|
25
|
+
installed: "Paquet(s) déjà installé(s)."
|
|
26
|
+
not_installed: "Paquet(s) non installé(s)."
|
|
27
|
+
|
|
28
|
+
header:
|
|
29
|
+
package: "Paquet"
|
|
30
|
+
version: "Version"
|
|
31
|
+
size: "Taille"
|
|
32
|
+
|
|
33
|
+
stat:
|
|
34
|
+
total_installed: "Nombre de paquets installés : %{number}"
|
|
35
|
+
explicitly_installed: "Nombre de paquets installés explicitement : %{number}"
|
|
36
|
+
space_used_in_cache: "Espace utilisé par les paquets dans le cache : %{size}"
|
|
37
|
+
|
|
38
|
+
warning:
|
|
39
|
+
upgrade: "Avertissement: upgrade est déprécié, utilisez safe-upgrade."
|
|
40
|
+
|
|
41
|
+
number:
|
|
42
|
+
separator:
|
|
43
|
+
thousands: " "
|
|
44
|
+
decimal: ","
|
data/src/apti/Apti.rb
ADDED
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#===============================================================================
|
|
3
|
+
#
|
|
4
|
+
# This file is part of Apti.
|
|
5
|
+
#
|
|
6
|
+
# Copyright (C) 2012-2014 by Florent Lévigne <florent.levigne at mailoo dot com>
|
|
7
|
+
# Copyright (C) 2013-2014 by Julien Rosset <jul.rosset at gmail dot com>
|
|
8
|
+
#
|
|
9
|
+
#
|
|
10
|
+
# Apti is free software: you can redistribute it and/or modify
|
|
11
|
+
# it under the terms of the GNU General Public License as published by
|
|
12
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
13
|
+
# (at your option) any later version.
|
|
14
|
+
#
|
|
15
|
+
# Apti is distributed in the hope that it will be useful,
|
|
16
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18
|
+
# GNU General Public License for more details.
|
|
19
|
+
#
|
|
20
|
+
# You should have received a copy of the GNU General Public License
|
|
21
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
22
|
+
#
|
|
23
|
+
#===============================================================================
|
|
24
|
+
|
|
25
|
+
module Apti
|
|
26
|
+
|
|
27
|
+
require 'i18n'
|
|
28
|
+
require_relative 'config/Config'
|
|
29
|
+
require_relative 'version'
|
|
30
|
+
|
|
31
|
+
class Apti
|
|
32
|
+
NEED_SUPERUSER_RIGHTS = [
|
|
33
|
+
'install', 'remove', 'purge', 'hold', 'unhold', 'keep', 'reinstall',
|
|
34
|
+
'markauto', 'unmarkauto', 'build-depends', 'build-dep', 'forbid-version',
|
|
35
|
+
'update', 'safe-upgrade', 'full-upgrade', 'keep-all', 'forget-new',
|
|
36
|
+
'clean', 'autoclean'
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# @!attribute config [r]
|
|
41
|
+
# @return [Apti::Config::Config] Config.
|
|
42
|
+
#
|
|
43
|
+
# @!attribute VERSION [r]
|
|
44
|
+
# @return [String] Apti's version.
|
|
45
|
+
attr_reader :config, :VERSION
|
|
46
|
+
|
|
47
|
+
# Reads the configuration file, and define locale.
|
|
48
|
+
#
|
|
49
|
+
# @return [void]
|
|
50
|
+
def initialize
|
|
51
|
+
@config = Config::Config.new
|
|
52
|
+
|
|
53
|
+
locales_path = File.dirname("#{__FILE__}") + '/../../locales'
|
|
54
|
+
lang = `echo $LANG`.split('_').first
|
|
55
|
+
|
|
56
|
+
if defined? I18n.enforce_available_locales
|
|
57
|
+
I18n.enforce_available_locales = true
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
I18n.load_path = Dir[File.join(locales_path, '*.yml')]
|
|
61
|
+
I18n.default_locale = :en
|
|
62
|
+
|
|
63
|
+
if defined? I18n.locale_available?
|
|
64
|
+
I18n.locale = lang if I18n.locale_available?(lang)
|
|
65
|
+
else
|
|
66
|
+
I18n.locale = lang
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Display help.
|
|
71
|
+
#
|
|
72
|
+
# @return [void]
|
|
73
|
+
def help
|
|
74
|
+
puts "usage: #{File.basename $0} commande"
|
|
75
|
+
puts 'Commandes:'
|
|
76
|
+
puts ' update'
|
|
77
|
+
puts ' safe-upgrade'
|
|
78
|
+
puts ' search package'
|
|
79
|
+
puts ' install package'
|
|
80
|
+
puts ' remove package'
|
|
81
|
+
puts ' others aptitude commande...'
|
|
82
|
+
puts ' stats'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Display version.
|
|
86
|
+
#
|
|
87
|
+
# @return [void]
|
|
88
|
+
def version
|
|
89
|
+
puts "apti #{VERSION}"
|
|
90
|
+
puts I18n.t(:using)
|
|
91
|
+
puts " aptitude #{`aptitude --version | head -n 1 | cut -d ' ' -f 2`}"
|
|
92
|
+
puts " ruby #{`ruby --version | cut -d ' ' -f 2`}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Install packages.
|
|
96
|
+
#
|
|
97
|
+
# @param package [String] List of packages to install.
|
|
98
|
+
#
|
|
99
|
+
# @return [void]
|
|
100
|
+
def install(package)
|
|
101
|
+
|
|
102
|
+
if package.eql? nil
|
|
103
|
+
usage
|
|
104
|
+
end
|
|
105
|
+
# Check if some packages does not exist.
|
|
106
|
+
packages_not_found = get_packages_not_found(package.split)
|
|
107
|
+
|
|
108
|
+
if !packages_not_found.empty?
|
|
109
|
+
puts I18n.t(:'error.package.not_found', packages: packages_not_found.join(' '))
|
|
110
|
+
exit 1
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Check if all packages are not already installed.
|
|
114
|
+
packages_already_installed = all_installed?(package.split)
|
|
115
|
+
|
|
116
|
+
if packages_already_installed
|
|
117
|
+
puts I18n.t(:'error.package.installed')
|
|
118
|
+
exit 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
aptitude_string = `aptitude install -VZs --allow-untrusted --assume-yes #{package}`
|
|
122
|
+
command = "aptitude install #{package}"
|
|
123
|
+
|
|
124
|
+
# If problem with dependencies: display aptitude's message.
|
|
125
|
+
if aptitude_string.include?('1)')
|
|
126
|
+
puts aptitude_string
|
|
127
|
+
exit 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
packages = aptitude_string.split(/ {2}/)
|
|
131
|
+
operation = I18n.t(:'operation.installing')
|
|
132
|
+
question = I18n.t(:'operation.question.installation')
|
|
133
|
+
|
|
134
|
+
if display_packages(packages, operation, 'install', question, aptitude_string.split(/\n/)[-2])
|
|
135
|
+
execute_command(command, true)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Remove / Purge packages.
|
|
140
|
+
#
|
|
141
|
+
# @param package [String] List of packages to remove / purge.
|
|
142
|
+
# @param purge [Boolean] True if purging packages, else removing.
|
|
143
|
+
#
|
|
144
|
+
# @return [void]
|
|
145
|
+
def remove(package, purge = false)
|
|
146
|
+
require_relative 'Package'
|
|
147
|
+
|
|
148
|
+
# Check if some packages does not exist.
|
|
149
|
+
packages_not_found = get_packages_not_found(package.split)
|
|
150
|
+
|
|
151
|
+
if !packages_not_found.empty?
|
|
152
|
+
puts I18n.t(:'error.package.not_found', packages: packages_not_found.join(' '))
|
|
153
|
+
exit 1
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Check if all packages are not uninstalled (only for remove).
|
|
157
|
+
if !purge
|
|
158
|
+
packages_not_installed = all_not_installed?(package.split)
|
|
159
|
+
|
|
160
|
+
if packages_not_installed
|
|
161
|
+
puts I18n.t(:'error.package.not_installed')
|
|
162
|
+
exit 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if purge
|
|
167
|
+
aptitude_string = `aptitude purge -VZs --assume-yes #{package}`
|
|
168
|
+
command = "aptitude purge #{package}"
|
|
169
|
+
operation = I18n.t(:'operation.purging')
|
|
170
|
+
question = I18n.t(:'operation.question.purge')
|
|
171
|
+
|
|
172
|
+
else
|
|
173
|
+
aptitude_string = `aptitude remove -VZs --assume-yes #{package}`
|
|
174
|
+
command = "aptitude remove #{package}"
|
|
175
|
+
operation = I18n.t(:'operation.removing')
|
|
176
|
+
question = I18n.t(:'operation.question.remove')
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# If problem with dependencies, wrong name given,
|
|
180
|
+
# or trying to remove a virtual package : display aptitude's message.
|
|
181
|
+
if aptitude_string.include?('1)') || aptitude_string.include?('«')
|
|
182
|
+
puts aptitude_string
|
|
183
|
+
exit 0
|
|
184
|
+
|
|
185
|
+
# If the package is not installed.
|
|
186
|
+
elsif !aptitude_string.include?(':')
|
|
187
|
+
puts I18n.t(:package_not_installed)
|
|
188
|
+
exit 0
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Remove the "p" parameter on packages to purge.
|
|
192
|
+
aptitude_string.sub!(/\{p\}/, '')
|
|
193
|
+
|
|
194
|
+
# Split packages.
|
|
195
|
+
packages = aptitude_string.split(/ {2}/)
|
|
196
|
+
|
|
197
|
+
if display_packages(packages, operation, 'remove', question, aptitude_string.split(/\n/)[-2])
|
|
198
|
+
execute_command(command, true)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Do upgrade (safe-upgrade or full-upgrade).
|
|
203
|
+
#
|
|
204
|
+
# @param packages [String] List of packages to upgrade.
|
|
205
|
+
# @param full_upgrade [Boolean] True if full-upgrade, else safe-upgrade.
|
|
206
|
+
#
|
|
207
|
+
# @return [void]
|
|
208
|
+
def upgrade(packages, full_upgrade = false)
|
|
209
|
+
if full_upgrade
|
|
210
|
+
aptitude_string = `aptitude full-upgrade -VZs --allow-untrusted --assume-yes #{packages}`
|
|
211
|
+
command = "aptitude full-upgrade #{packages}"
|
|
212
|
+
|
|
213
|
+
else
|
|
214
|
+
aptitude_string = `aptitude safe-upgrade -VZs --allow-untrusted --assume-yes #{packages}`
|
|
215
|
+
command = "aptitude safe-upgrade #{packages}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# If problem with dependencies, use aptitude.
|
|
219
|
+
if aptitude_string.include?('1)')
|
|
220
|
+
execute_command(command)
|
|
221
|
+
exit 0
|
|
222
|
+
|
|
223
|
+
# If there is no package to upgrade.
|
|
224
|
+
elsif !aptitude_string.include?(':')
|
|
225
|
+
puts I18n.t(:system_is_up_to_date)
|
|
226
|
+
exit 0
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Split packages.
|
|
230
|
+
packages = aptitude_string.split(/ {2}/)
|
|
231
|
+
operation = I18n.t(:'operation.upgrading')
|
|
232
|
+
question = I18n.t(:'operation.question.upgrade')
|
|
233
|
+
|
|
234
|
+
if display_packages(packages, operation, 'upgrade', question, aptitude_string.split(/\n/)[-2])
|
|
235
|
+
execute_command(command, true)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Search packages.
|
|
240
|
+
#
|
|
241
|
+
# @param package_name [String] Package(s) to search.
|
|
242
|
+
#
|
|
243
|
+
# @return [void]
|
|
244
|
+
def search(package_name)
|
|
245
|
+
require_relative 'Package'
|
|
246
|
+
|
|
247
|
+
aptitude_string = `aptitude search --disable-columns #{package_name}`
|
|
248
|
+
terminal_width = `tput cols`.to_i
|
|
249
|
+
|
|
250
|
+
# Information size (i, p, A, ...) : 6 seems to be good.
|
|
251
|
+
package_parameter_length_alignment = 6
|
|
252
|
+
|
|
253
|
+
get_search_packages(aptitude_string).each do |package|
|
|
254
|
+
print package.parameter
|
|
255
|
+
|
|
256
|
+
print ''.rjust(package_parameter_length_alignment - package.parameter.length)
|
|
257
|
+
|
|
258
|
+
# Display package name: if the package is installed, we display it in color.
|
|
259
|
+
if package.parameter.include?('i')
|
|
260
|
+
print "#{@config.colors.install.to_shell_color}#{package.name}#{get_color_for()}"
|
|
261
|
+
else
|
|
262
|
+
print package.name
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
print ''.rjust(@config.spaces.search - package.name.length)
|
|
266
|
+
|
|
267
|
+
size_of_line = package_parameter_length_alignment + @config.spaces.search + package.description.length
|
|
268
|
+
|
|
269
|
+
# If description is too long, we shorten it.
|
|
270
|
+
if size_of_line > terminal_width
|
|
271
|
+
package.description = package.description[0..(terminal_width - package_parameter_length_alignment - @config.spaces.search - 1)]
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
puts "#{@config.colors.description.to_shell_color}#{package.description.chomp}#{get_color_for()}"
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Print stats about packages.
|
|
279
|
+
#
|
|
280
|
+
# @return [void]
|
|
281
|
+
def stats
|
|
282
|
+
packages_installed = `dpkg --get-selections | grep -v deinstall | wc -l`
|
|
283
|
+
packages_installed_explicitly = `aptitude search '~i !~M' | wc -l`
|
|
284
|
+
cache_size = `du -sh /var/cache/apt/archives/ | cut -f 1`
|
|
285
|
+
|
|
286
|
+
puts "#{`lsb_release -ds`}\n"
|
|
287
|
+
|
|
288
|
+
puts I18n.t(:'stat.total_installed', number: packages_installed)
|
|
289
|
+
puts I18n.t(:'stat.explicitly_installed', number: packages_installed_explicitly)
|
|
290
|
+
puts I18n.t(:'stat.space_used_in_cache', size: cache_size)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Execute the command with superuser rights if needed.
|
|
294
|
+
#
|
|
295
|
+
# @param command [String] Command to execute.
|
|
296
|
+
# @param no_confirm [Boolean] If true execute the command without asking confirmation (--assume-yes).
|
|
297
|
+
#
|
|
298
|
+
# @return [void]
|
|
299
|
+
def execute_command(command, no_confirm = false)
|
|
300
|
+
if not NEED_SUPERUSER_RIGHTS.include?(command.split[1])
|
|
301
|
+
system(command)
|
|
302
|
+
|
|
303
|
+
elsif `groups`.split.include?('sudo')
|
|
304
|
+
if no_confirm && @config.no_confirm
|
|
305
|
+
system "sudo #{command} --assume-yes"
|
|
306
|
+
else
|
|
307
|
+
system "sudo #{command}"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
else
|
|
311
|
+
if no_confirm && @config.no_confirm
|
|
312
|
+
system "su -c '#{command} --assume-yes'"
|
|
313
|
+
else
|
|
314
|
+
system "su -c '#{command}'"
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
private
|
|
320
|
+
|
|
321
|
+
# Return an array of packages that does not exist.
|
|
322
|
+
#
|
|
323
|
+
# @param packages [Array<String>] Packages to check.
|
|
324
|
+
#
|
|
325
|
+
# @return [Array<String>] Packages not found.
|
|
326
|
+
def get_packages_not_found(packages)
|
|
327
|
+
require_relative 'Package'
|
|
328
|
+
|
|
329
|
+
not_found = []
|
|
330
|
+
|
|
331
|
+
packages.each do |package_name|
|
|
332
|
+
# If we use option (ex: -t sid), we don't check if packages exist.
|
|
333
|
+
if package_name =~ /^-.*$/
|
|
334
|
+
return []
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
pkg = Package.new
|
|
338
|
+
pkg.name = package_name
|
|
339
|
+
if !pkg.exist?
|
|
340
|
+
not_found.push(package_name)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
not_found
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Check if all packages are already installed.
|
|
348
|
+
#
|
|
349
|
+
# @param packages [Array<String>] Packages to check.
|
|
350
|
+
#
|
|
351
|
+
# @return [Boolean]
|
|
352
|
+
def all_installed?(packages)
|
|
353
|
+
require_relative 'Package'
|
|
354
|
+
|
|
355
|
+
all_installed = true
|
|
356
|
+
|
|
357
|
+
packages.each do |package_name|
|
|
358
|
+
pkg = Package.new
|
|
359
|
+
pkg.name = package_name
|
|
360
|
+
if !pkg.is_installed?
|
|
361
|
+
all_installed = false
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
all_installed
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Check if all packages are not installed.
|
|
369
|
+
#
|
|
370
|
+
# @param packages [Array<String>] Packages to check.
|
|
371
|
+
#
|
|
372
|
+
# @return [Boolean]
|
|
373
|
+
def all_not_installed?(packages)
|
|
374
|
+
require_relative 'Package'
|
|
375
|
+
|
|
376
|
+
all_not_installed = true
|
|
377
|
+
|
|
378
|
+
packages.each do |package_name|
|
|
379
|
+
pkg = Package.new
|
|
380
|
+
pkg.name = package_name
|
|
381
|
+
if pkg.is_installed?
|
|
382
|
+
all_not_installed = false
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
all_not_installed
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Separate packages in analysis parts (only for install, remove and upgrade).
|
|
390
|
+
#
|
|
391
|
+
# Return a Hash like +Hash{max, packages}+ with:
|
|
392
|
+
#
|
|
393
|
+
# * max: Apti::Package, Fake package with max lengths of all attributs.
|
|
394
|
+
# * packages: Array<Apti::Package>, Array of packages.
|
|
395
|
+
# @param packages_line [Array<String>] List of packages, as outputted by aptitude.
|
|
396
|
+
#
|
|
397
|
+
# @return [Hash]
|
|
398
|
+
def analysis_packages(packages_line)
|
|
399
|
+
require_relative 'Package'
|
|
400
|
+
|
|
401
|
+
max = Package.new
|
|
402
|
+
max.name = I18n.t(:'header.package')
|
|
403
|
+
max.version_static = ''
|
|
404
|
+
max.version_old = I18n.t(:'header.version')
|
|
405
|
+
max.version_new = ''
|
|
406
|
+
max.size_before_decimal = ''
|
|
407
|
+
max.size_after_decimal = ''
|
|
408
|
+
max.size_unit = ''
|
|
409
|
+
|
|
410
|
+
# Longest text for packages with no-revision (see below for explanations).
|
|
411
|
+
max_old_static = ''
|
|
412
|
+
|
|
413
|
+
thousands_separator = I18n.t(:'number.separator.thousands')
|
|
414
|
+
decimal_separator = I18n.t(:'number.separator.decimal')
|
|
415
|
+
|
|
416
|
+
packages = []
|
|
417
|
+
|
|
418
|
+
packages_line.delete_if { |package| package == '' || package == "\n" }
|
|
419
|
+
|
|
420
|
+
packages_line.each do |package_line|
|
|
421
|
+
# ex: brasero-common{a} [3.8.0-2 -> 3.8.0-5] <+11,2 MB>
|
|
422
|
+
# name : brasero-common
|
|
423
|
+
# parameter : a
|
|
424
|
+
# old version : 3.8.0
|
|
425
|
+
# old revision : 2
|
|
426
|
+
# new version : 3.8.0
|
|
427
|
+
# new revision : 5
|
|
428
|
+
# size before : +11
|
|
429
|
+
# size after : 2
|
|
430
|
+
# size_unit : MB
|
|
431
|
+
if package_line =~ /
|
|
432
|
+
^([[:alnum:]+.:-]*) # Package name.
|
|
433
|
+
(?:\{([[:alpha:]])\})? # Package parameter (a,u,...) if any.
|
|
434
|
+
\p{Space}
|
|
435
|
+
\[
|
|
436
|
+
([[:alnum:][:space:]+.:~]*) # Old version (without revision).
|
|
437
|
+
(?:-([[:alnum:][:space:]+.:~-]+))? # Old revision (if any).
|
|
438
|
+
(?:
|
|
439
|
+
\p{Space}->\p{Space} # Separator : ->
|
|
440
|
+
([[:alnum:]+.:~]*) # New version (without revision).
|
|
441
|
+
(?:-([[:alnum:]+.:~-]+))? # New revision (if any).
|
|
442
|
+
)?
|
|
443
|
+
\]
|
|
444
|
+
(?:\p{Space}<
|
|
445
|
+
([+-]? # Size symbol.
|
|
446
|
+
[[:digit:]]{1,3}(?:[#{thousands_separator}]?[[:digit:]]{3})*) # Size before decimal : integer part.
|
|
447
|
+
([#{decimal_separator}][[:digit:]]+)? # Size after decimal : decimal part.
|
|
448
|
+
\p{Space}
|
|
449
|
+
([[:alpha:]]+) # Size unit.
|
|
450
|
+
>)?$
|
|
451
|
+
/x
|
|
452
|
+
package = Package.new
|
|
453
|
+
|
|
454
|
+
package.name = Regexp.last_match[1]
|
|
455
|
+
package.parameter = Regexp.last_match[2]
|
|
456
|
+
|
|
457
|
+
if Regexp.last_match[3] == Regexp.last_match[5] # If old version (without revision) and new version (without revision) are identical => only "revision" upgrade.
|
|
458
|
+
package.version_static = Regexp.last_match(3); # Version (without revision).
|
|
459
|
+
package.version_old = Regexp.last_match(4); # Old revision.
|
|
460
|
+
package.version_new = Regexp.last_match(6); # New revision.
|
|
461
|
+
|
|
462
|
+
if package.version_static.length > max.version_static.length
|
|
463
|
+
max.version_static = package.version_static
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
if package.version_old.length > max.version_old.length
|
|
467
|
+
max.version_old = package.version_old
|
|
468
|
+
end
|
|
469
|
+
else # Else => "version" upgrade or not an upgrade.
|
|
470
|
+
package.version_static = nil # No "root" version : used to know if "revision" upgrade or not.
|
|
471
|
+
package.version_old = Regexp.last_match(3) # "Old" version => always present.
|
|
472
|
+
if !Regexp.last_match(4).nil?
|
|
473
|
+
package.version_old = package.version_old + "-" + Regexp.last_match(4) # Add revision only if exists
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
if !Regexp.last_match(5).nil? # And only if new version exist.
|
|
477
|
+
package.version_new = Regexp.last_match(5) # Remember it.
|
|
478
|
+
|
|
479
|
+
if !Regexp.last_match(6).nil?
|
|
480
|
+
package.version_new = package.version_new + "-" + Regexp.last_match(6)
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
if package.version_old.length > max_old_static.length
|
|
485
|
+
max_old_static = package.version_old
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
package.size_before_decimal = Regexp.last_match[7]
|
|
490
|
+
package.size_after_decimal = Regexp.last_match[8]
|
|
491
|
+
package.size_unit = Regexp.last_match[9]
|
|
492
|
+
|
|
493
|
+
if package.name.length > max.name.length
|
|
494
|
+
max.name = package.name
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
if !package.version_new.nil? && package.version_new.length > max.version_new.length
|
|
498
|
+
max.version_new = package.version_new
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
if !package.size_before_decimal.nil? && package.size_before_decimal.length > max.size_before_decimal.length
|
|
502
|
+
max.size_before_decimal = package.size_before_decimal
|
|
503
|
+
end
|
|
504
|
+
if !package.size_after_decimal.nil? && package.size_after_decimal.length > max.size_after_decimal.length
|
|
505
|
+
max.size_after_decimal = package.size_after_decimal
|
|
506
|
+
end
|
|
507
|
+
if !package.size_unit.nil? && package.size_unit.length > max.size_unit.length
|
|
508
|
+
max.size_unit = package.size_unit
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
packages.push(package)
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Check if longest text of no-revision upgrades (including install or remove) are greater than bloc of longest version and longest old revision of revision upgrades.
|
|
516
|
+
# Must be done AFTER treating all packages to ensure to use REALLY longest parts!
|
|
517
|
+
if max_old_static.length > (max.version_old.length + max.version_static.length)
|
|
518
|
+
# If so, this is first part ("root" version part) must be increased.
|
|
519
|
+
max.version_static = max_old_static.slice(0, max_old_static.length - max.version_old.length)
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
out = {}
|
|
523
|
+
out['max'] = max
|
|
524
|
+
out['packages'] = packages
|
|
525
|
+
|
|
526
|
+
out
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# Return an Array of the package(s) searched.
|
|
530
|
+
#
|
|
531
|
+
# @param aptitude_string [String] Output of aptitude search's command.
|
|
532
|
+
#
|
|
533
|
+
# @return [Array<Apti::Package>] Array of packages.
|
|
534
|
+
def get_search_packages(aptitude_string)
|
|
535
|
+
require_relative 'Package'
|
|
536
|
+
|
|
537
|
+
packages = []
|
|
538
|
+
|
|
539
|
+
aptitude_string.each_line do |package_line|
|
|
540
|
+
package = Package.new
|
|
541
|
+
|
|
542
|
+
package_str = package_line.split '- '
|
|
543
|
+
|
|
544
|
+
# Parameter and name, ex: i A aptitude-common.
|
|
545
|
+
package_parameter_and_name = package_str.first
|
|
546
|
+
|
|
547
|
+
package.description = ''
|
|
548
|
+
|
|
549
|
+
# Construct the description (all after the first '-').
|
|
550
|
+
name_passed = false
|
|
551
|
+
package_str.each do |str|
|
|
552
|
+
if not name_passed
|
|
553
|
+
name_passed = true
|
|
554
|
+
else
|
|
555
|
+
package.description.concat "- #{str }"
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
# The package name (without informations).
|
|
560
|
+
package.name = package_parameter_and_name.split.last
|
|
561
|
+
|
|
562
|
+
# Informations of the package: i, p, A, ...
|
|
563
|
+
package_info = package_parameter_and_name.split
|
|
564
|
+
package_info.pop
|
|
565
|
+
package.parameter = package_info.join(' ')
|
|
566
|
+
|
|
567
|
+
packages.push(package)
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
packages
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
# Display all packages of an operation (install, remove or upgrade).
|
|
574
|
+
#
|
|
575
|
+
# @param packages [Array<String>] List of packages as outputted by aptitude.
|
|
576
|
+
# @param operation [String] Operation requested : "Installing", "Upgrading" or "Removing".
|
|
577
|
+
# @param color [String] Color (Linux bash color notation) to use for old / current package version.
|
|
578
|
+
# @param question [String] Question to ask for continuing operation after displaying packages list.
|
|
579
|
+
# @param download_size [String] Aptitude's text about download sizes.
|
|
580
|
+
#
|
|
581
|
+
# @return [void]
|
|
582
|
+
def display_packages(packages, operation, color, question, download_size)
|
|
583
|
+
analysis = analysis_packages(packages)
|
|
584
|
+
max = analysis['max']
|
|
585
|
+
packages = analysis['packages']
|
|
586
|
+
|
|
587
|
+
explicit = []
|
|
588
|
+
dep_install = []
|
|
589
|
+
dep_remove = []
|
|
590
|
+
|
|
591
|
+
packages.each do |package|
|
|
592
|
+
case package.parameter
|
|
593
|
+
when 'a'
|
|
594
|
+
dep_install.push(package)
|
|
595
|
+
|
|
596
|
+
when 'u'
|
|
597
|
+
dep_remove.push(package)
|
|
598
|
+
|
|
599
|
+
else
|
|
600
|
+
explicit.push(package)
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# If we do an upgrade, we separate new revisions and new versions.
|
|
605
|
+
if operation.eql?(I18n.t(:'operation.upgrading'))
|
|
606
|
+
upgrade = true
|
|
607
|
+
|
|
608
|
+
upgrade_revisions = []
|
|
609
|
+
upgrade_versions = []
|
|
610
|
+
|
|
611
|
+
explicit.each do |package|
|
|
612
|
+
if package.version_static.nil?
|
|
613
|
+
upgrade_versions.push(package)
|
|
614
|
+
else
|
|
615
|
+
upgrade_revisions.push(package)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
if explicit.empty?
|
|
622
|
+
puts I18n.t(:'operation.nothing_to_do')
|
|
623
|
+
exit 1
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
print_header(max.name.length, max.version_all.length)
|
|
628
|
+
|
|
629
|
+
# If we have packages to upgrade, we display them at the end (after news to install, and those to remove).
|
|
630
|
+
if !upgrade
|
|
631
|
+
puts "#{@config.colors.text.to_shell_color}#{operation}#{get_color_for()}"
|
|
632
|
+
explicit.each { |package| display_package_line(package, max, color) }
|
|
633
|
+
puts ''
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
if !dep_install.empty?
|
|
637
|
+
puts "#{@config.colors.text.to_shell_color}#{I18n.t(:installing_for_dependencies)}#{get_color_for()}"
|
|
638
|
+
dep_install.each { |package| display_package_line(package, max, 'install') }
|
|
639
|
+
puts ''
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
if !dep_remove.empty?
|
|
643
|
+
puts "#{@config.colors.text.to_shell_color}#{I18n.t(:removing_unused_dependencies)}#{get_color_for()}"
|
|
644
|
+
dep_remove.each { |package| display_package_line(package, max, 'remove') }
|
|
645
|
+
puts ''
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
if upgrade
|
|
649
|
+
if !upgrade_revisions.empty?
|
|
650
|
+
puts "#{@config.colors.text.to_shell_color}#{I18n.t(:'operation.upgrading')} #{I18n.t(:'operation.new_revisions')}#{get_color_for()}"
|
|
651
|
+
upgrade_revisions.each { |package| display_package_line(package, max, color) }
|
|
652
|
+
puts ''
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
if !upgrade_versions.empty?
|
|
656
|
+
puts "#{@config.colors.text.to_shell_color}#{I18n.t(:'operation.upgrading')} #{I18n.t(:'operation.new_versions')}#{get_color_for()}"
|
|
657
|
+
upgrade_versions.each { |package| display_package_line(package, max, color) }
|
|
658
|
+
puts ''
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
# Size to download and install.
|
|
663
|
+
puts "#{download_size}"
|
|
664
|
+
|
|
665
|
+
answer = ''
|
|
666
|
+
while !answer.downcase.eql?('y') && !answer.downcase.eql?('n')
|
|
667
|
+
print "\n#{@config.colors.text.to_shell_color}#{question} (Y/n)#{get_color_for()} "
|
|
668
|
+
answer = STDIN.gets.chomp
|
|
669
|
+
if answer.empty?
|
|
670
|
+
answer = 'y'
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
answer.downcase.eql?('y')
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# Displaying the line of ONE package (for install, remove and upgrade).
|
|
678
|
+
#
|
|
679
|
+
# @param package [Apti::Package] The package to display.
|
|
680
|
+
# @param max [Apti::Package] Fake package with max lengths of all attributs.
|
|
681
|
+
# @param operation [String] Name of sub-variable of Apti::config.colors according to current operation (install, upgrade or remove).
|
|
682
|
+
#
|
|
683
|
+
# @return [void]
|
|
684
|
+
def display_package_line(package, max, operation)
|
|
685
|
+
# Name.
|
|
686
|
+
print " #{package.name}"
|
|
687
|
+
# Spaces.
|
|
688
|
+
print ''.rjust((max.name.length - package.name.length) + @config.spaces.columns)
|
|
689
|
+
|
|
690
|
+
# Package version (with revision if new version, without if new revision).
|
|
691
|
+
if package.version_static.nil?
|
|
692
|
+
print "#{get_color_for(operation, 'version.old')}#{package.version_old}"
|
|
693
|
+
else
|
|
694
|
+
print "#{get_color_for(operation, 'revision.static')}#{package.version_static}"
|
|
695
|
+
end
|
|
696
|
+
print "#{get_color_for()}"
|
|
697
|
+
|
|
698
|
+
if !package.version_new.nil?
|
|
699
|
+
print "#{''.rjust((max.version_old.length + max.version_static.length) - package.version_old.length - (package.version_static.nil? ? 0 : package.version_static.length))}"
|
|
700
|
+
if !package.version_static.nil?
|
|
701
|
+
print "#{get_color_for(operation, 'revision.old')}#{package.version_old}#{get_color_for()}"
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
print " -> #{get_color_for(operation, (package.version_static.nil? ? 'version' : 'revision') + '.new')}#{package.version_new}#{get_color_for}"
|
|
705
|
+
rjust_size = max.version_new.length - package.version_new.length
|
|
706
|
+
else
|
|
707
|
+
rjust_size = max.version_all.length - package.version_old.length
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
if @config.display_size && !package.size_before_decimal.nil?
|
|
711
|
+
line_size_after_length = (package.size_after_decimal.nil? ? 0 : package.size_after_decimal.length)
|
|
712
|
+
|
|
713
|
+
# Spaces.
|
|
714
|
+
print ''.rjust(rjust_size + @config.spaces.columns + max.size_before_decimal.length - package.size_before_decimal.length)
|
|
715
|
+
# Start color.
|
|
716
|
+
print @config.colors.size.to_shell_color
|
|
717
|
+
# Size.
|
|
718
|
+
print "#{package.size_before_decimal}#{package.size_after_decimal}"
|
|
719
|
+
# Spaces and unit.
|
|
720
|
+
print package.size_unit.rjust((max.size_after_decimal.length - line_size_after_length) + (max.size_unit.length) + @config.spaces.unit)
|
|
721
|
+
# End color.
|
|
722
|
+
print get_color_for()
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
print "\n"
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Get color of an "operation" (install, upgrade or remove).
|
|
729
|
+
# In case of "upgrade" operation, a sub-operation can be provide to access the desired color (examples in Apti::display_package_line code).
|
|
730
|
+
#
|
|
731
|
+
# If no "operation" is get, return the special Config::Color::STYLE_END color.
|
|
732
|
+
#
|
|
733
|
+
# @param operation [String] The "operation".
|
|
734
|
+
# @param sub_op [String] The sub-operation, separate levels with dot.
|
|
735
|
+
#
|
|
736
|
+
# @return [String] The shell notation of the color.
|
|
737
|
+
def get_color_for(operation = nil, sub_op = nil)
|
|
738
|
+
if operation.nil?
|
|
739
|
+
color = Config::Color.new(Config::Color::STYLE_END)
|
|
740
|
+
else
|
|
741
|
+
# Get the config field according to current operation.
|
|
742
|
+
color = @config.colors.send(operation)
|
|
743
|
+
|
|
744
|
+
if operation == 'upgrade' && !sub_op.nil?
|
|
745
|
+
# Must be do level by level because Object::send doesn't support dots (not like expected).
|
|
746
|
+
sub_op.split('.').each { |sub_var| color = color.send(sub_var) }
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
# Directly change color to shell notation.
|
|
751
|
+
color.to_shell_color
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
# Print header for install, remove and upgrade.
|
|
755
|
+
#
|
|
756
|
+
# @param largest_name [Fixnum] Largest size of package name.
|
|
757
|
+
# @param largest_version [Fixnum] Largest size of complete version (old / current AND new).
|
|
758
|
+
#
|
|
759
|
+
# @return [void]
|
|
760
|
+
def print_header(largest_name, largest_version)
|
|
761
|
+
terminal_width = `tput cols`.to_i
|
|
762
|
+
|
|
763
|
+
# Top line.
|
|
764
|
+
terminal_width.times do
|
|
765
|
+
print '='
|
|
766
|
+
end
|
|
767
|
+
print "\n"
|
|
768
|
+
|
|
769
|
+
# Column's names.
|
|
770
|
+
header_package = I18n.t(:'header.package')
|
|
771
|
+
header_version = I18n.t(:'header.version')
|
|
772
|
+
header_size = I18n.t(:'header.size')
|
|
773
|
+
|
|
774
|
+
print " #{header_package}"
|
|
775
|
+
print "#{''.rjust(largest_name - header_package.length + @config.spaces.columns)}"
|
|
776
|
+
print "#{header_version}"
|
|
777
|
+
if @config.display_size
|
|
778
|
+
print "#{''.rjust(largest_version - header_version.length + @config.spaces.columns + 1)}"
|
|
779
|
+
print "#{header_size}"
|
|
780
|
+
end
|
|
781
|
+
print "\n"
|
|
782
|
+
|
|
783
|
+
# Bottom line.
|
|
784
|
+
terminal_width.times do
|
|
785
|
+
print '='
|
|
786
|
+
end
|
|
787
|
+
print "\n"
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
end
|
|
791
|
+
end
|