View | Details | Raw Unified | Return to bug 32471
Collapse All | Expand All

(-)umc/setup.xml (-1 lines)
 Lines 20-26    Link Here 
20
		<command name="setup/lang/countrycodes" function="lang_countrycodes"></command>
20
		<command name="setup/lang/countrycodes" function="lang_countrycodes"></command>
21
		<command name="setup/net/interfaces" function="net_interfaces"></command>
21
		<command name="setup/net/interfaces" function="net_interfaces"></command>
22
		<command name="setup/net/dhclient" function="net_dhclient"></command>
22
		<command name="setup/net/dhclient" function="net_dhclient"></command>
23
		<command name="setup/software/components" function="software_components"></command>
24
		<command name="setup/keymap/save" function="save_keymap"></command>
23
		<command name="setup/keymap/save" function="save_keymap"></command>
25
	</module>
24
	</module>
26
</umc>
25
</umc>
(-)umc/python/setup/__init__.py (-10 / +3 lines)
 Lines 65-71    Link Here 
65
65
66
RE_IPV4 = re.compile(r'^interfaces/(([^/_]+)(_[0-9])?)/(address|netmask)$')
66
RE_IPV4 = re.compile(r'^interfaces/(([^/_]+)(_[0-9])?)/(address|netmask)$')
67
RE_IPV6_DEFAULT = re.compile(r'^interfaces/([^/]+)/ipv6/default/(prefix|address)$')
67
RE_IPV6_DEFAULT = re.compile(r'^interfaces/([^/]+)/ipv6/default/(prefix|address)$')
68
RE_SPACE = re.compile(r'\s+')
69
RE_SSL = re.compile(r'^ssl/.*')
68
RE_SSL = re.compile(r'^ssl/.*')
70
69
71
class Instance(umcm.Base):
70
class Instance(umcm.Base):
 Lines 79-84    Link Here 
79
		os.umask( 0022 )
78
		os.umask( 0022 )
80
79
81
	def init( self ):
80
	def init( self ):
81
		locale.setlocale( locale.LC_ALL, str( self.locale ) )
82
		util.installer_i18n.set_language( str( self.locale ) )
82
		util.installer_i18n.set_language( str( self.locale ) )
83
		os.environ[ 'LC_ALL' ] =  str( self.locale )
83
		os.environ[ 'LC_ALL' ] =  str( self.locale )
84
84
 Lines 344-351    Link Here 
344
		_check('server/role', lambda x: not(orgValues.get('joined')) or (orgValues.get('server/role') == values.get('server/role')), _('The system role may not change on a system that has already joined to domain.'))
344
		_check('server/role', lambda x: not(orgValues.get('joined')) or (orgValues.get('server/role') == values.get('server/role')), _('The system role may not change on a system that has already joined to domain.'))
345
345
346
		# basis
346
		# basis
347
		components = RE_SPACE.split(values.get('components', ''))
347
		components = values.get('components', [])
348
		packages = set(reduce(lambda x, y: x + y, [ i.split(':') for i in components ]))
348
		packages = set(reduce(lambda x, y: x + y, [ comp.get('defaultpackages', []) for comp in components if comp.get('is_installed')]))
349
349
350
		_check('hostname', util.is_hostname, _('The hostname is not a valid fully qualified domain name in lowercase (e.g. host.example.com).'))
350
		_check('hostname', util.is_hostname, _('The hostname is not a valid fully qualified domain name in lowercase (e.g. host.example.com).'))
351
		_check('hostname', lambda x: len(x) <= 13, _('A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.'), critical=('univention-samba' in packages or 'univention-samba4' in packages))
351
		_check('hostname', lambda x: len(x) <= 13, _('A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.'), critical=('univention-samba' in packages or 'univention-samba4' in packages))
 Lines 522-531    Link Here 
522
		"interface" and optionally the key "timeout" (in seconds).'''
522
		"interface" and optionally the key "timeout" (in seconds).'''
523
523
524
		return util.dhclient(interface, timeout)
524
		return util.dhclient(interface, timeout)
525
526
	@simple_response
527
	def software_components(self, role=None):
528
		'''Return a list of all available software packages. Entries have the properties
529
		"id", "label", and "packages" which is an array of the Debian package names.'''
530
		return [ { 'id': i['id'], 'label': i['Name'], 'packages': i['Packages'] }
531
				for i in util.get_components(role=role) ]
(-)umc/python/setup/util.py (-66 / +34 lines)
 Lines 40-61    Link Here 
40
import univention.config_registry
40
import univention.config_registry
41
import time
41
import time
42
import re
42
import re
43
import sys
44
import apt
45
import psutil
43
import psutil
46
import csv
44
import csv
47
import imp
48
import os.path
45
import os.path
49
46
50
from univention.lib.i18n import Translation
51
from univention.management.console.log import MODULE
47
from univention.management.console.log import MODULE
52
48
53
installer_i18n = Translation( 'installer', localedir = '/lib/univention-installer/locale' )
49
from univention.management.console.modules.appcenter.app_center import Application
50
from univention.lib.package_manager import PackageManager
54
51
55
if not '/lib/univention-installer/' in sys.path:
56
	sys.path.append('/lib/univention-installer/')
57
import package_list
58
59
ucr=univention.config_registry.ConfigRegistry()
52
ucr=univention.config_registry.ConfigRegistry()
60
ucr.load()
53
ucr.load()
61
54
 Lines 73-78    Link Here 
73
RE_IPV4_TYPE = re.compile('interfaces/[^/]*/type')
66
RE_IPV4_TYPE = re.compile('interfaces/[^/]*/type')
74
RE_LOCALE = re.compile(r'([^.@ ]+).*')
67
RE_LOCALE = re.compile(r'([^.@ ]+).*')
75
68
69
read_only_package_manager = PackageManager(
70
	info_handler=MODULE.process,
71
	step_handler=None,
72
	error_handler=MODULE.warn,
73
	lock=False,
74
)
75
76
# list of all needed UCR variables
76
# list of all needed UCR variables
77
UCR_VARIABLES = [
77
UCR_VARIABLES = [
78
	# common
78
	# common
 Lines 123-130    Link Here 
123
	else:
123
	else:
124
		values['timezone']=''
124
		values['timezone']=''
125
125
126
	# get installed components
126
	# get components
127
	values['components'] = ' '.join([icomp['id'] for icomp in get_installed_components()])
127
	values['components'] = get_components()
128
128
129
	return values
129
	return values
130
130
 Lines 160-179    Link Here 
160
160
161
	# add lists with all packages that should be removed/installed on the system
161
	# add lists with all packages that should be removed/installed on the system
162
	if 'components' in newValues:
162
	if 'components' in newValues:
163
		regSpaces = re.compile(r'\s+')
163
		components_selected = dict([comp['id'], comp.get('is_installed', False)] for comp in newValues['components'])
164
		selectedComponents = set(regSpaces.split(newValues.get('components', '')))
164
		all_components = get_components()
165
		currentComponents = set([icomp['id'] for icomp in get_installed_components()])
166
		allComponents = set([ icomp['id'] for icomp in get_components() ])
167
165
168
		# get all packages that shall be removed
166
		# get all packages that shall be removed
169
		removeComponents = list(allComponents & (currentComponents - selectedComponents))
167
		remove_apps = [ app for app in all_components if app['is_installed'] and not components_selected.get(app['id'], False) ]
170
		newValues['packages_remove'] = ' '.join([ i.replace(':', ' ') for i in removeComponents ])
168
		newValues['apps_remove'] = ' '.join([app['id'] for app in remove_apps])
171
169
172
		allComponents = set([ icomp['id'] for icomp in get_components(role=role) ])
170
		all_components = get_components(role=role)
173
171
174
		# get all packages that shall be installed
172
		# get all packages that shall be installed
175
		installComponents = list(allComponents & (selectedComponents - currentComponents))
173
		install_apps = [ app for app in all_components if not app['is_installed'] and components_selected.get(app['id'], False) ]
176
		newValues['packages_install'] = ' '.join([ i.replace(':', ' ') for i in installComponents ])
174
		newValues['apps_install'] = ' '.join([app['id'] for app in install_apps])
177
175
178
#	if 'locale' in newValues:
176
#	if 'locale' in newValues:
179
#		# js returns locale as list
177
#		# js returns locale as list
 Lines 235-245    Link Here 
235
233
236
	# fractions of setup scripts
234
	# fractions of setup scripts
237
	FRACTIONS = {
235
	FRACTIONS = {
238
		'10_basis/12domainname'	:  5,
236
		'10_basis/12domainname' :  5,
239
		'10_basis/14ldap_basis'	: 10,
237
		'10_basis/14ldap_basis' : 10,
240
		'30_net/10interfaces'	:  5,
238
		'30_net/10interfaces' :  5,
241
		'30_net/11ipv6interfaces'	:  5,
239
		'30_net/11ipv6interfaces' :  5,
242
		'50_software/10software'	: 50,
240
		'50_software/10software' : 5, # deprecated, probably not used
241
		'50_software/20apps' : 50,
243
		}
242
		}
244
243
245
	# current status
244
	# current status
 Lines 552-600    Link Here 
552
	return dhcp_dict
551
	return dhcp_dict
553
552
554
def get_components(role=None):
553
def get_components(role=None):
555
	'''Returns a list of components that may be installed on the current system.'''
554
	'''Returns a list of all components.'''
556
555
557
	# get all package sets that are available for the current system role
556
	components = []
558
	if not role:
557
	read_only_package_manager.reopen_cache()
559
		role = ucr.get('server/role')
558
	Application._get_category_translations(fake=True)
559
	for app in Application.all(force_reread=True, only_local=True):
560
		if 'UCS components' in app.get('categories'):
561
			if role and app.get('serverrole') and role not in app.get('serverrole'):
562
				continue
563
			components.append(app.to_dict(read_only_package_manager))
564
	return components
560
565
561
	# reload for correct locale
562
	imp.reload(package_list)
563
	pkglist = [ jpackage for icategory in package_list.PackageList 
564
			for jpackage in icategory['Packages']
565
			if 'all' in jpackage['Possible'] or role in jpackage['Possible'] ]
566
567
	# filter whitelisted packages
568
	whitelist = ucr.get('system/setup/packages/whitelist')
569
	if whitelist:
570
		whitelist = whitelist.split(' ')
571
		pkglist = [ipkg for ipkg in pkglist if all(jpkg in whitelist for jpkg in ipkg['Packages'])]
572
573
	# filter blacklisted packages
574
	blacklist = ucr.get('system/setup/packages/blacklist')
575
	if blacklist:
576
		blacklist = blacklist.split(' ')
577
		pkglist = [ipkg for ipkg in pkglist if not any(jpkg in blacklist for jpkg in ipkg['Packages'])]
578
579
	# generate a unique ID for each component
580
	for ipkg in pkglist:
581
		ipkg['id'] = ':'.join(ipkg['Packages'])
582
		ipkg[ 'Description' ] = installer_i18n.translate( ipkg[ 'Description' ] )
583
		ipkg[ 'Name' ] = installer_i18n.translate( ipkg[ 'Name' ] )
584
585
	return pkglist
586
587
def get_installed_packages():
588
	'''Returns a list of all installed packages on the system.'''
589
	cache = apt.Cache()
590
	return [ p.name for p in cache if p.is_installed ]
591
592
def get_installed_components():
593
	'''Returns a list of components that are currently fully installed on the system.'''
594
	allPackages = set(get_installed_packages())
595
	allComponents = get_components()
596
	return [ icomp for icomp in allComponents if not len(set(icomp['Packages']) - allPackages) ]
597
598
# from univention-installer/installer/modules/70_net.py
566
# from univention-installer/installer/modules/70_net.py
599
def is_proxy(proxy):
567
def is_proxy(proxy):
600
	if proxy and proxy != 'http://' and proxy != 'https://':
568
	if proxy and proxy != 'http://' and proxy != 'https://':
(-)umc/js/setup/SoftwarePage.js (-144 / +41 lines)
 Lines 33-212    Link Here 
33
	"dojo/_base/lang",
33
	"dojo/_base/lang",
34
	"dojo/_base/array",
34
	"dojo/_base/array",
35
	"umc/tools",
35
	"umc/tools",
36
	"umc/widgets/Form",
36
	"umc/widgets/StandbyMixin",
37
	"umc/widgets/Page",
37
	"umc/modules/appcenter/AppCenterPage",
38
	"umc/widgets/MultiSelect",
39
	"umc/i18n!umc/modules/setup"
38
	"umc/i18n!umc/modules/setup"
40
], function(declare, lang, array, tools, Form, Page, MultiSelect, _) {
39
], function(declare, lang, array, tools, StandbyMixin, AppCenterPage, _) {
41
40
42
	return declare("umc.modules.setup.SoftwarePage", [ Page ], {
41
	return declare("umc.modules.setup.SoftwarePage", [ AppCenterPage, StandbyMixin ], {
43
		// summary:
42
		liveSearch: false,
44
		//		This class renderes a detail page containing subtabs and form elements
43
		addMissingAppButton: false,
45
		//		in order to edit UDM objects.
44
		standbyDuringUpdateApplications: false,
46
45
47
		// system-setup-boot
46
		title: _('Software'),
48
		wizard_mode: false,
47
		headerText: _('Software settings'),
48
		helpText: _('Via the <i>software settings</i>, particular software components may be installed or removed.'),
49
49
50
		// __systemsetup__ user is logged in at local firefox session
50
		getAppCenterSeen: function() {
51
		local_mode: false,
51
			return true;
52
53
		umcpCommand: tools.umcpCommand,
54
55
		// internal reference to the formular containing all form widgets of an UDM object
56
		_form: null,
57
58
		_orgComponents: undefined,
59
60
		_noteShowed: false,
61
62
		postMixInProperties: function() {
63
			this.inherited(arguments);
64
65
			this.title = _('Software');
66
			this.headerText = _('Software settings');
67
			this.helpText = _('Via the <i>software settings</i>, particular software components may be installed or removed.');
68
		},
52
		},
69
53
70
		buildRendering: function() {
54
		showDetails: function(app) {
71
			this.inherited(arguments);
55
			// do not show anything. toggle installed flag
72
56
			app.is_installed = !app.is_installed;
73
			var widgets = [{
57
			this._grid.store.notify(app, app.id);
74
				type: MultiSelect,
58
			// TODO: show warning? notes?
75
				name: 'components',
76
				label: _('Installed software components'),
77
				umcpCommand: this.umcpCommand,
78
				dynamicValues: 'setup/software/components',
79
				dynamicOptions: {},
80
				sortDynamicValues: false,
81
				style: 'width: 500px;',
82
				height: '200px'
83
			}];
84
85
			var layout = [{
86
				label: _('Installation of software components'),
87
				layout: ['components']
88
			}];
89
90
			this._form = new Form({
91
				widgets: widgets,
92
				layout: layout,
93
				scrollable: true
94
			});
95
			this._form.on('submit', lang.hitch(this, 'onSave'));
96
97
			this.addChild(this._form);
98
99
			// show notes when samba 3/4 is selected
100
			this.own(this._form.getWidget('components').watch('value', lang.hitch(this, function(name, oldVal, newVal) {
101
				array.forEach(['samba', 'samba4'], function(ikey) {
102
					var r = new RegExp('univention-' + ikey + '\\b');
103
					if (array.some(this._getInstalledComponents(), function(icomponent) { return  (r.test(icomponent)); }, this)) {
104
						this._showNote(ikey);
105
					}
106
				}, this);
107
			})));
108
109
			// show notes for changes in the software settings
110
			this.own(this._form.getWidget('components').watch('value', lang.hitch(this, function() {
111
				this._showNote('software');
112
			})));
113
114
			// remember which notes have already been shown
115
			this._noteShowed = { };
116
			this._myNotes = {
117
				samba: _('It is not possible to mix NT and Active Directory compatible domaincontroller. Make sure the existing UCS domain is NT-compatible (Samba 3).'),
118
				samba4: _('It is not possible to mix NT and Active Directory compatible domaincontroller. Make sure the existing UCS domain is Active Directory-compatible (Samba 4).'),
119
				software: _('Installing or removing software components may result in restarting or stopping services. This can have severe side-effects when the system is in productive use at the moment.')
120
			};
121
		},
59
		},
122
60
123
		_showNote: function(key) {
124
			if (!(key in this._noteShowed) || !this._form.getWidget('components').focused) {
125
				// make sure key exists
126
				return;
127
			}
128
129
			if (!this._noteShowed[key]) {
130
				this._noteShowed[key] = true;
131
				this.addNote(this._myNotes[key]);
132
			}
133
		},
134
135
		setValues: function(vals) {
61
		setValues: function(vals) {
136
			// set dynamicOption to get list of components corresponding to selected system role
62
			this._components = lang.clone(vals.components);
137
			this._form.getWidget('components').set('dynamicOptions', { role: vals['server/role'] });
138
139
			// get a dict of all installed components and initialise component list
140
			var components = (vals.components || '').split(/\s+/);
141
			this._form.getWidget('components').setInitialValue(components, true);
142
143
			if (this._orgComponents === undefined) {
63
			if (this._orgComponents === undefined) {
144
				this._orgComponents = {};
64
				this._orgComponents = lang.clone(this._components);
145
				array.forEach(components, function(icomponent) {
146
					if(icomponent !== "") {
147
						this._orgComponents[icomponent] = true;
148
					}
149
				}, this);
150
			}
65
			}
66
			this.updateApplications();
67
			this.set('appQuery', {
68
				serverrole: {
69
					test: function(serverrole) {
70
						return serverrole.length === 0 || array.indexOf(serverrole, vals['server/role']) >= 0;
71
					}
72
				}
73
			});
74
		},
151
75
152
			// handling of notes
76
		getApplications: function() {
153
			this._noteShowed = { };
77
			return this._components || [];
154
			var role = vals['server/role'];
155
			if (role == 'domaincontroller_backup' || role == 'domaincontroller_slave') {
156
				// only show samba notes on backup/slave
157
				this._noteShowed.samba = false;
158
				this._noteShowed.samba4 = false;
159
			}
160
			// show note when changing software only on a joined system in productive mode
161
			this._noteShowed.software = this.wizard_mode;
162
			this.clearNotes();
163
		},
78
		},
164
79
165
		getValues: function() {
80
		getValues: function() {
166
			return {
81
			return {
167
				components: this._form.getWidget('components').get('value').join(' ')
82
				components: this.getApplications()
168
			};
83
			};
169
		},
84
		},
170
85
171
		_getComponents: function() {
172
			// return a dict of currently selected components
173
			var components = {};
174
			array.forEach(this._form.get('value').components, function(icomp) {
175
				components[icomp] = true;
176
			});
177
			return components;
178
		},
179
180
		_getRemovedComponents: function() {
86
		_getRemovedComponents: function() {
181
			// if a previously installed component has been deselected
87
			// if a previously installed component has been deselected
182
			// -> uninstall all its packages
88
			// -> uninstall all its packages
183
			var components = [];
89
			return array.filter(this._orgComponents, lang.hitch(this, function(component) {
184
			var selectedComponents = this._getComponents();
90
				return component.is_installed && !this._grid.store.get(component.id).is_installed;
185
			tools.forIn(this._orgComponents, function(icomponent) {
91
			}));
186
				if (!(icomponent in selectedComponents)) {
187
					components.push(icomponent);
188
				}
189
			});
190
			return components;
191
		},
92
		},
192
93
193
		_getInstalledComponents: function() {
94
		_getInstalledComponents: function() {
194
			// if a previously not/partly installed component has been selected
95
			// if a previously not/partly installed component has been selected
195
			// -> install all its packages
96
			// -> install all its packages
196
			var components = [];
97
			return array.filter(this._orgComponents, lang.hitch(this, function(component) {
197
			tools.forIn(this._getComponents(), function(icomponent) {
98
				return !component.is_installed && this._grid.store.get(component.id).is_installed;
198
				if (!(icomponent in this._orgComponents)) {
99
			}));
199
					components.push(icomponent);
200
				}
201
			}, this);
202
			return components;
203
		},
100
		},
204
101
205
		getSummary: function() {
102
		getSummary: function() {
206
			// a list of all components with their labels
103
			// a list of all components with their labels
207
			var allComponents = {};
104
			var allComponents = {};
208
			array.forEach(this._form.getWidget('components').getAllItems(), function(iitem) {
105
			array.forEach(this._grid.store.data, function(component) {
209
				allComponents[iitem.id] = iitem.label;
106
				allComponents[component.id] = component.name;
210
			});
107
			});
211
108
212
			// get changed components
109
			// get changed components
 Lines 218-224    Link Here 
218
			var components = [];
115
			var components = [];
219
			if (installComponents.length) {
116
			if (installComponents.length) {
220
				components = array.map(installComponents, function(icomponent) {
117
				components = array.map(installComponents, function(icomponent) {
221
					return allComponents[icomponent];
118
					return allComponents[icomponent.id];
222
				});
119
				});
223
				result.push({
120
				result.push({
224
					variables: ['components'],
121
					variables: ['components'],
 Lines 228-234    Link Here 
228
			}
125
			}
229
			if (removeComponents.length) {
126
			if (removeComponents.length) {
230
				components = array.map(removeComponents, function(icomponent) {
127
				components = array.map(removeComponents, function(icomponent) {
231
					return allComponents[icomponent];
128
					return allComponents[icomponent.id];
232
				});
129
				});
233
				result.push({
130
				result.push({
234
					variables: ['components'],
131
					variables: ['components'],
(-)umc/js/setup.js (-1 / +1 lines)
 Lines 120-126    Link Here 
120
		},
120
		},
121
121
122
		renderPages: function(ucr, values) {
122
		renderPages: function(ucr, values) {
123
			this._progressBar = new ProgressBar();
123
			this._progressBar = new ProgressBar({});
124
			this.own(this._progressBar);
124
			this.own(this._progressBar);
125
			this.standby(true);
125
			this.standby(true);
126
126
(-)usr/lib/univention-system-setup/scripts/50_software/20apps (+94 lines)
Line 0    Link Here 
1
#!/usr/bin/python2.6
2
# -*- coding: utf-8 -*-
3
#
4
# Univention System Setup
5
#  apps installation script
6
#
7
# Copyright 2013 Univention GmbH
8
#
9
# http://www.univention.de/
10
#
11
# All rights reserved.
12
#
13
# The source code of this program is made available
14
# under the terms of the GNU Affero General Public License version 3
15
# (GNU AGPL V3) as published by the Free Software Foundation.
16
#
17
# Binary versions of this program provided by Univention to you as
18
# well as other copyrighted, protected or trademarked materials like
19
# Logos, graphics, fonts, specific documentations and configurations,
20
# cryptographic keys etc. are subject to a license agreement between
21
# you and Univention and not subject to the GNU AGPL V3.
22
#
23
# In the case you use this program under the terms of the GNU AGPL V3,
24
# the program is provided in the hope that it will be useful,
25
# but WITHOUT ANY WARRANTY; without even the implied warranty of
26
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
# GNU Affero General Public License for more details.
28
#
29
# You should have received a copy of the GNU Affero General Public
30
# License with the Debian GNU/Linux or Univention distribution in file
31
# /usr/share/common-licenses/AGPL-3; if not, see
32
# <http://www.gnu.org/licenses/>.
33
import os.path
34
35
from univention.management.console.modules.setup.setup_script import AptScript, main, _
36
from univention.management.console.modules.appcenter.app_center import Application
37
from univention.updater import UniventionUpdater
38
from univention.management.console.modules.appcenter.util import ComponentManager
39
from univention.config_registry import ConfigRegistry
40
41
class AppScript(AptScript):
42
	name = _('Configuring software components')
43
	script_name = os.path.abspath(__file__)
44
	brutal_apt_options = False
45
46
	def up(self):
47
		super(AppScript, self).up()
48
49
		# get this scripts configuration options
50
		self.apps_remove = self.get_profile_var_list('apps_remove')
51
		self.apps_install = self.get_profile_var_list('apps_install')
52
		ucr = ConfigRegistry()
53
		uu = UniventionUpdater(False)
54
		self.component_manager = ComponentManager(ucr, uu)
55
56
	def inner_run(self):
57
		if not (self.apps_remove or self.apps_install):
58
			# nothing to do. dont autoremove either
59
			return True
60
		# +1 for update
61
		ntasks = len(self.apps_remove) + len(self.apps_install) + 1
62
		self.steps(ntasks * 100)
63
64
		# apt-get update
65
		if self.update():
66
			self.finish_task('Update')
67
		else:
68
			return False
69
		base_package = self.get_package_for_role(self.current_server_role)
70
		if base_package is None:
71
			return False
72
		else:
73
			self.set_always_install(base_package)
74
75
		Application._get_category_translations(fake=True)
76
		Application.all(only_local=True)
77
		for app_id in self.apps_remove:
78
			# apt-get remove *app.defaultpackages
79
			app = Application.find(app_id)
80
			app.uninstall(self.package_manager, self.component_manager)
81
			self.finish_task(app.name)
82
83
		for app_id in self.apps_install:
84
			# apt-get install *app.defaultpackages
85
			app = Application.find(app_id)
86
			app.install(self.package_manager, self.component_manager)
87
			self.finish_task(app.name)
88
89
		return True
90
91
if __name__ == '__main__':
92
	script = AppScript()
93
	main(script)
94
(-)debian/control (+1 lines)
 Lines 22-27    Link Here 
22
 shell-univention-lib,
22
 shell-univention-lib,
23
 python-univention-lib (>= 1.0.25-1),
23
 python-univention-lib (>= 1.0.25-1),
24
 console-tools,
24
 console-tools,
25
 univention-management-console-module-appcenter,
25
 shell-univention-lib (>= 3.0.1-1),
26
 shell-univention-lib (>= 3.0.1-1),
26
 python-univention-lib (>= 3.0.1-1)
27
 python-univention-lib (>= 3.0.1-1)
27
Recommends: univention-management-console-module-setup
28
Recommends: univention-management-console-module-setup

Return to bug 32471