Merge lp:~townsend/libertine/refactor-lcm into lp:libertine

Proposed by Christopher Townsend
Status: Merged
Approved by: Larry Price
Approved revision: 258
Merged at revision: 257
Proposed branch: lp:~townsend/libertine/refactor-lcm
Merge into: lp:libertine
Diff against target: 1274 lines (+561/-586)
2 files modified
python/libertine/ContainersConfig.py (+299/-0)
tools/libertine-container-manager (+262/-586)
To merge this branch: bzr merge lp:~townsend/libertine/refactor-lcm
Reviewer Review Type Date Requested Status
Larry Price Approve
Libertine CI Bot continuous-integration Approve
Review via email: mp+298252@code.launchpad.net

Commit message

Add a new ContainersConfig Python class for managing all things ContainersConfig.json.
Add a new LibertineContainerManager Python class for handling the functions of l-c-m.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:255
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/12/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/94
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/62
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/62
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/62
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/62
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/62
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/62
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/78/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/97
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/82
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/82
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/82
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/75/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/75/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/75
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/75/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/12/rebuild

review: Approve (continuous-integration)
Revision history for this message
Larry Price (larryprice) wrote :

See inline diff comments.

Also, were we in the habit of two newlines between functions? It's all good to me as long as we stay consistent.

lp:~townsend/libertine/refactor-lcm updated
256. By Christopher Townsend

Some more refactoring based on review comments.

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:256
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/14/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/98
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/66
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/66
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/66
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/66
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/66
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/66
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/81/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/101
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/86
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/86
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/86
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/79/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/79/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/79/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/79/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/79/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/79
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/79/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/14/rebuild

review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Thanks!

As discussed on IRC, double space vs. single space is a pyflakes thing of functions outside a class vs. inside a class.

I did not merge _test_key_value_exists() and _test_array_object_key_value_exists() as you suggested because I think doing so may introduce more complexity in what I'm trying to do there:)

lp:~townsend/libertine/refactor-lcm updated
257. By Christopher Townsend

Handle some cases where containers may not exist.

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:257
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/16/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/100
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/67
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/67
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/67
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/67
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/67
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/67
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/83/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/103
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/88
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/88
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/88
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/81/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/81/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/81/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/81/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/81/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/81
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/81/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/16/rebuild

review: Approve (continuous-integration)
Revision history for this message
Larry Price (larryprice) wrote :

been poking around at some error cases and found a couple of places that need fixing (see inline)

review: Needs Fixing
lp:~townsend/libertine/refactor-lcm updated
258. By Christopher Townsend

Add missing sys module.
Fix typo.

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:258
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/18/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/104
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=default/71
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/71
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=yakkety,testname=default/71
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=vivid+overlay,testname=default/71
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/71
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=yakkety,testname=default/71
    None: https://jenkins.canonical.com/libertine/job/lp-generic-update-mp/85/console
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/107
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=vivid+overlay/92
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=xenial+overlay/92
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-1-sourcepkg/release=yakkety/92
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=vivid+overlay/85/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/85/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=yakkety/85/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=vivid+overlay/85/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/85/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/85
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=yakkety/85/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/18/rebuild

review: Approve (continuous-integration)
Revision history for this message
Larry Price (larryprice) wrote :

lgtm!

i also filed a bug for unrelated issues with accessing the log files of corrupt containers: https://bugs.launchpad.net/libertine/+bug/1596661

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'python/libertine/ContainersConfig.py'
--- python/libertine/ContainersConfig.py 1970-01-01 00:00:00 +0000
+++ python/libertine/ContainersConfig.py 2016-06-27 17:59:37 +0000
@@ -0,0 +1,299 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import fcntl
16import json
17import libertine.utils
18import os
19import sys
20
21
22def read_container_config_file():
23 container_list = {}
24 container_config_file = libertine.utils.get_libertine_database_file_path()
25
26 if (os.path.exists(container_config_file) and
27 os.path.getsize(container_config_file) != 0):
28 with open(container_config_file, 'r') as fd:
29 container_list = json.load(fd)
30
31 return container_list
32
33
34def write_container_config_file(container_list):
35 container_config_file = libertine.utils.get_libertine_database_file_path()
36
37 with open(container_config_file, 'w') as fd:
38 fcntl.lockf(fd, fcntl.LOCK_EX)
39 json.dump(container_list, fd, sort_keys=True, indent=4)
40 fd.write('\n')
41 fcntl.lockf(fd, fcntl.LOCK_UN)
42
43
44class ContainersConfig(object):
45
46 def __init__(self):
47 self.container_list = read_container_config_file()
48
49 if "defaultContainer" in self.container_list:
50 self.default_container_id = self.container_list['defaultContainer']
51 else:
52 self.default_container_id = None
53
54 """
55 Private helper methods
56 """
57 def _get_container_entry(self, container_id):
58 if not self.container_list:
59 return None
60
61 for container in self.container_list['containerList']:
62 if container['id'] == container_id:
63 return container
64
65 return None
66
67 def _get_value_by_key(self, container_id, key):
68 container = self._get_container_entry(container_id)
69
70 if not container or key not in container:
71 return None
72 else:
73 return container[key]
74
75 def _get_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key):
76 for item in self._get_value_by_key(container_id, array_key):
77 if item[object_key] == matcher:
78 return item[key]
79
80 def _set_value_by_key(self, container_id, key, value):
81 container = self._get_container_entry(container_id)
82
83 if not container:
84 return
85
86 if type(value) is str:
87 container[key] = value
88 elif type(value) is dict:
89 if key not in container:
90 container[key] = [value]
91 else:
92 container[key].append(value)
93
94 write_container_config_file(self.container_list)
95
96 def _set_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key, value):
97 container = self._get_container_entry(container_id)
98
99 if not container:
100 return
101
102 for item in container[array_key]:
103 if item[object_key] == matcher:
104 item[key] = value
105 write_container_config_file(self.container_list)
106 return
107
108 def _delete_array_object_by_key_value(self, container_id, array_key, object_key, value):
109 container = self._get_container_entry(container_id)
110
111 if not container:
112 return
113
114 for item in container[array_key]:
115 if item[object_key] == value:
116 container[array_key].remove(item)
117 write_container_config_file(self.container_list)
118 return
119
120 def _test_key_value_exists(self, container_id, key, value=None):
121 key_value = self._get_value_by_key(container_id, key)
122
123 if not key_value:
124 return False
125 elif key == 'id':
126 return True
127 elif key_value == value:
128 return True
129 else:
130 return False
131
132 def _test_array_object_key_value_exists(self, container_id, array_key, object_key, value):
133 array = self._get_value_by_key(container_id, array_key)
134
135 if not array:
136 return False
137
138 for item in array:
139 if item[object_key] == value:
140 return True
141
142 return False
143
144 """
145 Miscellaneous ContainersConfig.json operations
146 """
147 def _find_duplicate_container_entry(self, container_list, container_id):
148 for container in container_list['containerList']:
149 if container['id'] == container_id:
150 return container
151
152 return None
153
154 def merge_container_config_files(self, filepath):
155 merged_json = []
156
157 with open(filepath, 'r') as fd:
158 merge_source = json.load(fd)
159
160 if "containerList" in self.container_list:
161 # Finds any duplicate entries and assumes we want to update the main config
162 # with entries from the merge source.
163 for i, container in enumerate(self.container_list['containerList']):
164 merge_container = self._find_duplicate_container_entry(merge_source, container['id'])
165 if merge_container:
166 self.container_list['containerList'][i] = merge_container
167 merge_source['containerList'].remove(merge_container)
168
169 # Merges in any remaining non-duplicate entries.
170 for container in merge_source['containerList']:
171 self.container_list['containerList'].append(container)
172
173 else:
174 self.container_list = merge_source
175
176 write_container_config_file(self.container_list)
177
178 def check_container_id(self, container_id):
179 if container_id and not self.container_exists(container_id):
180 print("Container id \'%s\' does not exist." % container_id, file=sys.stderr)
181 sys.exit(1)
182 elif not container_id:
183 return self.get_default_container_id()
184
185 return container_id
186
187 def get_default_container_id(self):
188 return self.default_container_id
189
190 def set_default_container_id(self, container_id, write_json=False):
191 self.default_container_id = container_id
192 self.container_list['defaultContainer'] = container_id
193
194 if write_json:
195 write_container_config_file(self.container_list)
196
197 def clear_default_container_id(self, write_json=False):
198 self.default_container_id = None
199 self.container_list.pop('defaultContainer', None)
200
201 if write_json:
202 write_container_config_file(self.container_list)
203
204 """
205 Operations for the container itself.
206 """
207 def add_new_container(self, container_id, container_name, container_type, container_distro):
208 container_obj = {'id': container_id, 'installStatus': 'new', 'type': container_type,
209 'distro': container_distro, 'name': container_name, 'installedApps': []}
210
211 if "defaultContainer" not in self.container_list:
212 self.set_default_container_id(container_id)
213
214 if "containerList" not in self.container_list:
215 self.container_list['containerList'] = [container_obj]
216 else:
217 self.container_list['containerList'].append(container_obj)
218
219 write_container_config_file(self.container_list)
220
221 def delete_container(self, container_id):
222 if not self.container_list:
223 print("Unable to delete container. No containers defined.")
224 sys.exit(1)
225
226 container = self._get_container_entry(container_id)
227
228 self.container_list['containerList'].remove(container)
229
230 # Set a new defaultContainer if the current default is being deleted.
231 if self.container_list['defaultContainer'] == container_id and self.container_list['containerList']:
232 self.set_default_container_id(self.container_list['containerList'][0]['id'])
233 # Remove the defaultContainer if there are no more containers left.
234 elif not self.container_list['containerList']:
235 self.clear_default_container_id()
236
237 write_container_config_file(self.container_list)
238
239 def update_container_install_status(self, container_id, new_status):
240 self._set_value_by_key(container_id, 'installStatus', new_status)
241
242 def container_exists(self, container_id):
243 return self._test_key_value_exists(container_id, 'id')
244
245 def update_container_multiarch_support(self, container_id, multiarch):
246 if multiarch == 'enabled' and libertine.utils.get_host_architecture() == 'i386':
247 multiarch = 'disabled'
248
249 self._set_value_by_key(container_id, 'multiarch', multiarch)
250
251 def get_container_multiarch_support(self, container_id):
252 multiarch_support = self._get_value_by_key(container_id, 'multiarch')
253
254 if multiarch_support == None:
255 return 'disabled'
256 else:
257 return multiarch_support
258
259 """
260 Operations for archive (PPA) maintenance in a Libertine container.
261 """
262 def add_container_archive(self, container_id, archive_name):
263 archive_obj = {'archiveName': archive_name, 'archiveStatus': 'new'}
264 self._set_value_by_key(container_id, 'extraArchives', archive_obj)
265
266 def delete_container_archive(self, container_id, archive_name):
267 self._delete_array_object_by_key_value(container_id, 'extraArchives',
268 'archiveName', archive_name)
269
270 def update_archive_install_status(self, container_id, archive_name, new_status):
271 self._set_array_object_value_by_key(container_id, 'extraArchives', 'archiveName',
272 archive_name, 'archiveStatus', new_status)
273
274 def archive_exists(self, container_id, archive_name):
275 return self._test_array_object_key_value_exists(container_id, 'extraArchives', 'archiveName',
276 archive_name)
277
278 """
279 Operations for package maintenance in a Libertine container.
280 """
281 def add_new_package(self, container_id, package_name):
282 package_obj = {'packageName': package_name, 'appStatus': 'new'}
283 self._set_value_by_key(container_id, 'installedApps', package_obj)
284
285 def delete_package(self, container_id, package_name):
286 self._delete_array_object_by_key_value(container_id, 'installedApps',
287 'packageName', package_name)
288
289 def update_package_install_status(self, container_id, package_name, new_status):
290 self._set_array_object_value_by_key(container_id, 'installedApps', 'packageName',
291 package_name, 'appStatus', new_status)
292
293 def get_package_install_status(self, container_id, package_name):
294 return self._get_array_object_value_by_key(container_id, 'installedApps', 'packageName',
295 package_name, 'appStatus')
296
297 def package_exists(self, container_id, package_name):
298 return self._test_array_object_key_value_exists(container_id, 'installedApps', 'packageName',
299 package_name)
0300
=== modified file 'tools/libertine-container-manager'
--- tools/libertine-container-manager 2016-06-20 15:15:38 +0000
+++ tools/libertine-container-manager 2016-06-27 17:59:37 +0000
@@ -17,8 +17,6 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19import argparse19import argparse
20import fcntl
21import json
22import libertine.utils20import libertine.utils
23import lsb_release21import lsb_release
24import getpass22import getpass
@@ -27,75 +25,9 @@
27import sys25import sys
2826
29from apt.debfile import DebPackage27from apt.debfile import DebPackage
30from distro_info import UbuntuDistroInfo, DistroDataOutdated28from distro_info import UbuntuDistroInfo
31from libertine import LibertineContainer29from libertine import LibertineContainer
3230from libertine.ContainersConfig import ContainersConfig
33
34def find_duplicate_container_entry(container_list, container_id):
35 for container in container_list['containerList']:
36 if container['id'] == container_id:
37 return container
38
39 return None
40
41
42def merge_container_config_files(filepath):
43 merged_json = []
44 main_config = read_container_config_file()
45
46 with open(filepath, 'r') as fd:
47 merge_source = json.load(fd)
48
49 if "containerList" in main_config:
50 # Finds any duplicate entries and assumes we want to update the main config
51 # with entries from the merge source.
52 for i, container in enumerate(main_config['containerList']):
53 merge_container = find_duplicate_container_entry(merge_source, container['id'])
54 if merge_container:
55 main_config['containerList'][i] = merge_container
56 merge_source['containerList'].remove(merge_container)
57
58 # Merges in any remaining non-duplicate entries.
59 for container in merge_source['containerList']:
60 main_config['containerList'].append(container)
61
62 else:
63 main_config = merge_source
64
65 write_container_config_file(main_config)
66
67
68def read_container_config_file():
69 container_list = {}
70 container_config_file = libertine.utils.get_libertine_database_file_path()
71
72 if (os.path.exists(container_config_file) and
73 os.path.getsize(container_config_file) != 0):
74 with open(container_config_file, 'r') as fd:
75 container_list = json.load(fd)
76
77 return container_list
78
79
80def write_container_config_file(container_list):
81 container_config_file = libertine.utils.get_libertine_database_file_path()
82
83 with open(container_config_file, 'w') as fd:
84 fcntl.lockf(fd, fcntl.LOCK_EX)
85 json.dump(container_list, fd, sort_keys=True, indent=4)
86 fd.write('\n')
87 fcntl.lockf(fd, fcntl.LOCK_UN)
88
89
90def get_default_container_id():
91 default_container_id = None
92
93 container_list = read_container_config_file()
94
95 if "defaultContainer" in container_list:
96 default_container_id = container_list['defaultContainer']
97
98 return default_container_id
9931
10032
101def select_container_type():33def select_container_type():
@@ -142,512 +74,254 @@
142 return None74 return None
14375
14476
145def update_container_install_status(container_id, new_status):77class LibertineContainerManager(object):
146 container_list = read_container_config_file()78
14779 def __init__(self):
148 for container in container_list['containerList']:80 self.containers_config = ContainersConfig()
149 if container['id'] == container_id:81
150 container['installStatus'] = new_status82 def create(self, args):
15183 password = None
152 write_container_config_file(container_list)84
153 break85 if args.distro and not is_distro_valid(args.distro, args.force):
15486 print("Invalid distro %s" % args.distro, file=sys.stderr)
15587 sys.exit(1)
156def update_container_multiarch_support(container_id, multiarch):88
157 container_list = read_container_config_file()89 if args.id and self.containers_config.container_exists(args.id):
15890 print("Container id \'%s\' is already used." % args.id, file=sys.stderr)
159 if multiarch == 'enabled' and libertine.utils.get_host_architecture() == 'i386':91 sys.exit(1)
160 multiarch = 'disabled'92 elif not args.id:
16193 args.id = get_unique_container_id(distro)
162 for container in container_list['containerList']:94
163 if container['id'] == container_id:95 if not args.type:
164 container['multiarch'] = multiarch96 container_type = select_container_type()
16597 else:
166 write_container_config_file(container_list)98 container_type = args.type
167 break99
168100 if not args.distro:
169101 args.distro = get_host_distro_release()
170def get_container_multiarch_support(container_id):102 elif container_type == "chroot":
171 container_list = read_container_config_file()103 host_distro = get_host_distro_release()
172104
173 for container in container_list['containerList']:105 if args.distro != host_distro:
174 if container['id'] == container_id:106 print("The container distribution needs to match the host ditribution for chroot"
175 if not 'multiarch' in container:107 " based containers. Please either use \'%s\' or omit the -d/--distro option."
176 return 'disabled'108 % host_distro)
177 else:109 sys.exit(1)
178 return container['multiarch']110
179111 if not args.name:
180112 args.name = "Ubuntu \'" + get_distro_codename(args.distro) + "\'"
181def update_archive_install_status(container_id, archive_name, new_status):113
182 container_list = read_container_config_file()114 if container_type == "lxc":
183115 if args.password:
184 for container in container_list['containerList']:116 password = args.password
185 if container['id'] == container_id:117 elif sys.stdin.isatty():
186 for archive in container['extraArchives']:118 print("Your user password is required for creating a Libertine container.")
187 if archive['archiveName'] == archive_name:119 password = getpass.getpass()
188 archive['archiveStatus'] = new_status120 else:
189 write_container_config_file(container_list)121 password = sys.stdin.readline().rstrip()
190 return122
191123 self.containers_config.add_new_container(args.id, args.name, container_type, args.distro)
192124
193def add_container_archive(container_id, archive_name):
194 container_list = read_container_config_file()
195
196 for container in container_list['containerList']:
197 if container['id'] == container_id:
198 archive_obj = {'archiveName': archive_name, 'archiveStatus': 'new'}
199
200 if 'extraArchives' not in container:
201 container['extraArchives'] = [archive_obj]
202 else:
203 container['extraArchives'].append(archive_obj)
204
205 write_container_config_file(container_list)
206 break
207
208
209def delete_container_archive(container_id, archive_name):
210 container_list = read_container_config_file()
211
212 for container in container_list['containerList']:
213 if container['id'] == container_id:
214 for archive in container['extraArchives']:
215 if archive['archiveName'] == archive_name:
216 container['extraArchives'].remove(archive)
217 write_container_config_file(container_list)
218 return
219
220 print("%s does not exist." % archive_name)
221 sys.exit(1)
222
223
224def archive_exists(container_id, archive_name):
225 container_list = read_container_config_file()
226
227 for container in container_list['containerList']:
228 if container['id'] == container_id:
229 if 'extraArchives' not in container:
230 return False
231 else:
232 for archive in container['extraArchives']:
233 if archive['archiveName'] == archive_name:
234 return True
235
236 return False
237
238
239def add_new_container(id, name, type, distro):
240 if not os.path.exists(libertine.utils.get_libertine_database_dir_path()):
241 os.makedirs(libertine.utils.get_libertine_database_dir_path())
242
243 container_list = read_container_config_file()
244
245 container_obj = {'id': id, 'installStatus': 'new', 'type': type,
246 'distro': distro, 'name': name, 'installedApps': []}
247
248 if "defaultContainer" not in container_list:
249 container_list['defaultContainer'] = id
250
251 if "containerList" not in container_list:
252 container_list['containerList'] = [container_obj]
253 else:
254 container_list['containerList'].append(container_obj)
255
256 write_container_config_file(container_list)
257
258
259def delete_container(container_id):
260 container_list = read_container_config_file()
261
262 if not container_list:
263 print("Unable to delete container. No containers defined.")
264 sys.exit(1)
265
266 for container in container_list['containerList']:
267 if container['id'] == container_id:
268 container_list['containerList'].remove(container)
269
270 # Set a new defaultContainer if the current default is being deleted.
271 if container_list['defaultContainer'] == container_id and container_list['containerList']:
272 container_list['defaultContainer'] = container_list['containerList'][0]['id']
273 # Remove the defaultContainer if there are no more containers left.
274 elif not container_list['containerList']:
275 del container_list['defaultContainer']
276
277 write_container_config_file(container_list)
278 break
279
280
281def package_exists(container_id, package_name):
282 container_list = read_container_config_file()
283
284 if not container_list:
285 return False
286
287 for container in container_list['containerList']:
288 if container['id'] == container_id:
289 for package in container['installedApps']:
290 if package['packageName'] == package_name:
291 return True
292
293 return False
294
295
296def update_package_install_status(container_id, package_name, new_status):
297 container_list = read_container_config_file()
298
299 for container in container_list['containerList']:
300 if container['id'] == container_id:
301 for package in container['installedApps']:
302 if package['packageName'] == package_name:
303 package['appStatus'] = new_status
304 write_container_config_file(container_list)
305 return
306
307
308def get_package_install_status(container_id, package_name):
309 container_list = read_container_config_file()
310
311 for container in container_list['containerList']:
312 if container['id'] == container_id:
313 for package in container['installedApps']:
314 if package['packageName'] == package_name:
315 return package['appStatus']
316
317
318def add_new_package(container_id, package_name):
319 container_list = read_container_config_file()
320
321 if not container_list:
322 print("No containers defined. Please create a new container before installing a package.")
323 sys.exit(1)
324
325 for container in container_list['containerList']:
326 if container['id'] == container_id:
327 package_obj = {'packageName': package_name, 'appStatus': 'new'}
328
329 if not container['installedApps']:
330 container['installedApps'] = [package_obj]
331 else:
332 container['installedApps'].append(package_obj)
333
334 write_container_config_file(container_list)
335 break
336
337
338def delete_package(container_id, package_name):
339 container_list = read_container_config_file()
340
341 if not container_list:
342 print("No containers defined. Please create a new container before installing a package.")
343 sys.exit(1)
344
345 for container in container_list['containerList']:
346 if container['id'] == container_id:
347 for package in container['installedApps']:
348 if package['packageName'] == package_name:
349 container['installedApps'].remove(package)
350 write_container_config_file(container_list)
351 return
352
353 print("Package \'%s\' does not exist." % package_name)
354 sys.exit(1)
355
356
357def create(args):
358 password = None
359
360 if args.distro and not is_distro_valid(args.distro, args.force):
361 print("Invalid distro %s" % args.distro, file=sys.stderr)
362 sys.exit(1)
363
364 if args.id and libertine.utils.container_exists(args.id):
365 print("Container id \'%s\' is already used." % args.id, file=sys.stderr)
366 sys.exit(1)
367 elif not args.id:
368 args.id = get_unique_container_id(distro)
369
370 if not args.type:
371 container_type = select_container_type()
372 else:
373 container_type = args.type
374
375 if not args.distro:
376 args.distro = get_host_distro_release()
377 elif container_type == "chroot":
378 host_distro = get_host_distro_release()
379
380 if args.distro != host_distro:
381 print("The container distribution needs to match the host ditribution for chroot"
382 " based containers. Please either use \'%s\' or omit the -d/--distro option."
383 % host_distro)
384 sys.exit(1)
385
386 if not args.name:
387 args.name = "Ubuntu \'" + get_distro_codename(args.distro) + "\'"
388
389 if container_type == "lxc":
390 if args.password:
391 password = args.password
392 elif sys.stdin.isatty():
393 print("Your user password is required for creating a Libertine container.")
394 password = getpass.getpass()
395 else:
396 password = sys.stdin.readline().rstrip()
397
398 add_new_container(args.id, args.name, container_type, args.distro)
399
400 multiarch = 'disabled'
401 if args.multiarch:
402 multiarch = 'enabled'
403 update_container_multiarch_support(args.id, multiarch)
404
405 container = LibertineContainer(args.id)
406 update_container_install_status(args.id, "installing")
407 if not container.create_libertine_container(password, args.multiarch, args.verbosity):
408 delete_container(args.id)
409 sys.exit(1)
410 update_container_install_status(args.id, "ready")
411
412 libertine.utils.refresh_libertine_scope()
413
414
415def destroy_container_by_id(id):
416 container = LibertineContainer(id)
417 update_container_install_status(id, "removing")
418 container.destroy_libertine_container()
419 update_container_install_status(id, "removed")
420 delete_container(id)
421
422
423def destroy(args):
424 if args.id and not libertine.utils.container_exists(args.id):
425 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
426 sys.exit(1)
427 elif not args.id:
428 args.id = get_default_container_id()
429
430 destroy_container_by_id(args.id)
431
432 libertine.utils.refresh_libertine_scope()
433
434
435def install_package(args):
436 if args.id and not libertine.utils.container_exists(args.id):
437 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
438 sys.exit(1)
439 elif not args.id:
440 args.id = get_default_container_id()
441
442 is_debian_package = args.package.endswith('.deb')
443
444 if is_debian_package:
445 if os.path.exists(args.package):
446 package = DebPackage(args.package).pkgname
447 else:
448 print("%s does not exist." % args.package)
449 sys.exit(1)
450 else:
451 package = args.package
452
453 if package_exists(args.id, package):
454 if not is_debian_package:
455 print("Package \'%s\' is already installed." % package)
456 sys.exit(1)
457 else:
458 add_new_package(args.id, package)
459
460 container = LibertineContainer(args.id)
461
462 update_package_install_status(args.id, package, "installing")
463 if not container.install_package(args.package, args.verbosity, args.readline):
464 delete_package(args.id, package)
465 sys.exit(1)
466
467 update_package_install_status(args.id, package, "installed")
468
469 libertine.utils.refresh_libertine_scope()
470
471
472def remove_package_by_name(container_id, package_name, verbosity=1, readline=False):
473 fallback_status = get_package_install_status(container_id, package_name)
474 update_package_install_status(container_id, package_name, "removing")
475
476 container = LibertineContainer(container_id)
477 if not container.remove_package(package_name, verbosity, readline):
478 update_package_install_status(container_id, package_name, fallback_status)
479 return False
480
481 update_package_install_status(container_id, package_name, "removed")
482 delete_package(container_id, package_name)
483
484 return True
485
486
487def remove_package(args):
488 if args.id and not libertine.utils.container_exists(args.id):
489 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
490 sys.exit(1)
491 elif not args.id:
492 args.id = get_default_container_id()
493
494 if get_package_install_status(args.id, args.package) != 'installed':
495 print("Package \'%s\' is not installed." % args.package)
496 sys.exit(1)
497
498 if not remove_package_by_name(args.id, args.package, args.verbosity, args.readline):
499 sys.exit(1)
500
501 libertine.utils.refresh_libertine_scope()
502
503
504def search_cache(args):
505 if args.id and not libertine.utils.container_exists(args.id):
506 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
507 sys.exit(1)
508 elif not args.id:
509 args.id = get_default_container_id()
510
511 container = LibertineContainer(args.id)
512 if container.search_package_cache(args.search_string) is not 0:
513 sys.exit(1)
514
515
516def update(args):
517 if args.id and not libertine.utils.container_exists(args.id):
518 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
519 sys.exit(1)
520 elif not args.id:
521 args.id = get_default_container_id()
522
523 container = LibertineContainer(args.id)
524
525 update_container_install_status(args.id, "updating")
526 if container.update_libertine_container(args.verbosity) is not 0:
527 update_container_install_status(args.id, "ready")
528 sys.exit(1)
529
530 update_container_install_status(args.id, "ready")
531
532
533def list(args):
534 containers = libertine.utils.Libertine.list_containers()
535 for container in containers:
536 print("%s" % container)
537
538
539def list_apps(args):
540 if args.id and not libertine.utils.container_exists(args.id):
541 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
542 sys.exit(1)
543 elif not args.id:
544 args.id = get_default_container_id()
545
546 container = LibertineContainer(args.id)
547 print(container.list_app_launchers(use_json=args.json))
548
549
550def exec(args):
551 if args.id and not libertine.utils.container_exists(args.id):
552 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
553 sys.exit(1)
554 elif not args.id:
555 args.id = get_default_container_id()
556
557 container = LibertineContainer(args.id)
558
559 if not container.exec_command(args.command):
560 sys.exit(1)
561
562
563def delete_archive_by_name(container_id, archive_name):
564 update_archive_install_status(container_id, archive_name, 'removing')
565 if LibertineContainer(container_id).configure_command('delete-archive', archive_name) is not 0:
566 return False
567 delete_container_archive(container_id, archive_name)
568 return True
569
570
571def configure(args):
572 if args.id and not libertine.utils.container_exists(args.id):
573 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
574 sys.exit(1)
575 elif not args.id:
576 args.id = get_default_container_id()
577
578 container = LibertineContainer(args.id)
579
580 if args.multiarch and libertine.utils.get_host_architecture() == 'amd64':
581 multiarch = 'disabled'125 multiarch = 'disabled'
582 if args.multiarch == 'enable':126 if args.multiarch == 'enable':
583 multiarch = 'enabled'127 multiarch = 'enabled'
584128 self.containers_config.update_container_multiarch_support(args.id, multiarch)
585 current_multiarch = get_container_multiarch_support(args.id)129
586 if current_multiarch == multiarch:130 container = LibertineContainer(args.id)
587 print("i386 multiarch support is already %s" % multiarch)131 self.containers_config.update_container_install_status(args.id, "installing")
588 sys.exit(1)132 if not container.create_libertine_container(password, args.multiarch, args.verbosity):
589133 self.containers_config.delete_container(args.id)
590 if container.configure_command('multiarch', args.multiarch) is not 0:134 sys.exit(1)
591 sys.exit(1)135 self.containers_config.update_container_install_status(args.id, "ready")
592136
593 update_container_multiarch_support(args.id, multiarch)137 libertine.utils.refresh_libertine_scope()
594138
595 elif args.add_archive:139 def destroy_container_by_id(self, id):
596 if archive_exists(args.id, args.add_archive):140 container = LibertineContainer(id)
597 print("%s already added in container." % args.add_archive)141
598 sys.exit(1)142 self.containers_config.update_container_install_status(id, "removing")
599143 container.destroy_libertine_container()
600 add_container_archive(args.id, args.add_archive)144 self.containers_config.update_container_install_status(id, "removed")
601 update_archive_install_status(args.id, args.add_archive, 'installing')145 self.containers_config.delete_container(id)
602 if container.configure_command('add-archive', args.add_archive) is not 0:146
603 delete_container_archive(args.id, args.add_archive)147 def destroy(self, args):
604 sys.exit(1)148 args.id = self.containers_config.check_container_id(args.id)
605149
606 update_archive_install_status(args.id, args.add_archive, 'installed')150 self.destroy_container_by_id(args.id)
607151
608 elif args.delete_archive:152 libertine.utils.refresh_libertine_scope()
609 if not archive_exists(args.id, args.delete_archive):153
610 print("%s is not added in container." % args.delete_archive)154 def install_package(self, args):
611 sys.exit(1)155 container_id = self.containers_config.check_container_id(args.id)
612156
613 if not delete_archive_by_name(args.id, args.delete_archive):157 is_debian_package = args.package.endswith('.deb')
614 sys.exit(1)158
615159 if is_debian_package:
616160 if os.path.exists(args.package):
617def merge(args):161 package = DebPackage(args.package).pkgname
618 merge_container_config_files(args.file)162 else:
619163 print("%s does not exist." % args.package)
620164 sys.exit(1)
621def fix_integrity(args):165 else:
622 for container in read_container_config_file()['containerList']:166 package = args.package
623 if container['installStatus'] != 'ready':167
624 destroy_container_by_id(container['id'])168 if self.containers_config.package_exists(container_id, package):
625 continue169 if not is_debian_package:
626 LibertineContainer(container['id']).exec_command('dpkg --configure -a')170 print("Package \'%s\' is already installed." % package)
627171 sys.exit(1)
628 for package in container['installedApps']:172 else:
629 if package['appStatus'] != 'installed':173 self.containers_config.add_new_package(container_id, package)
630 remove_package_by_name(container['id'], package['packageName'])174
631 if 'extraArchives' in container:175 container = LibertineContainer(container_id)
632 for archive in container['extraArchives']:176
633 if archive['archiveStatus'] != 'installed':177 self.containers_config.update_package_install_status(container_id, package, "installing")
634 delete_archive_by_name(container['id'], archive['archiveName'])178 if not container.install_package(args.package, args.verbosity, args.readline):
635179 self.containers_config.delete_package(container_id, package)
636180 sys.exit(1)
637def set_default(args):181
638 if args.clear:182 self.containers_config.update_package_install_status(container_id, package, "installed")
639 container_list = read_container_config_file()183
640 container_list.pop('defaultContainer', None)184 libertine.utils.refresh_libertine_scope()
641 write_container_config_file(container_list)185
642 sys.exit(0)186 def remove_package_by_name(self, container_id, package_name, verbosity=1, readline=False):
643187 fallback_status = self.containers_config.get_package_install_status(container_id, package_name)
644 if not libertine.utils.container_exists(args.id):188 self.containers_config.update_package_install_status(container_id, package_name, "removing")
645 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)189
646 sys.exit(1)190 container = LibertineContainer(container_id)
647191 if not container.remove_package(package_name, verbosity, readline):
648 container_list = read_container_config_file()192 self.containers_config.update_package_install_status(container_id, package_name, fallback_status)
649 container_list['defaultContainer'] = args.id193 return False
650 write_container_config_file(container_list)194
195 self.containers_config.update_package_install_status(container_id, package_name, "removed")
196 self.containers_config.delete_package(container_id, package_name)
197
198 return True
199
200 def remove_package(self, args):
201 container_id = self.containers_config.check_container_id(args.id)
202
203 if self.containers_config.get_package_install_status(container_id, args.package) != 'installed':
204 print("Package \'%s\' is not installed." % args.package)
205 sys.exit(1)
206
207 if not self.remove_package_by_name(container_id, args.package, args.verbosity, args.readline):
208 sys.exit(1)
209
210 libertine.utils.refresh_libertine_scope()
211
212 def search_cache(self, args):
213 container_id = self.containers_config.check_container_id(args.id)
214
215 container = LibertineContainer(container_id)
216 if container.search_package_cache(args.search_string) is not 0:
217 sys.exit(1)
218
219 def update(self, args):
220 container_id = self.containers_config.check_container_id(args.id)
221
222 container = LibertineContainer(container_id)
223
224 self.containers_config.update_container_install_status(container_id, "updating")
225 if container.update_libertine_container(args.verbosity) is not 0:
226 self.containers_config.update_container_install_status(container_id, "ready")
227 sys.exit(1)
228
229 self.containers_config.update_container_install_status(container_id, "ready")
230
231 def list(self, args):
232 containers = libertine.utils.Libertine.list_containers()
233 for container in containers:
234 print("%s" % container)
235
236 def list_apps(self, args):
237 container_id = self.containers_config.check_container_id(args.id)
238
239 container = LibertineContainer(container_id)
240 print(container.list_app_launchers(use_json=args.json))
241
242 def exec(self, args):
243 container_id = self.containers_config.check_container_id(args.id)
244
245 container = LibertineContainer(container_id)
246
247 if not container.exec_command(args.command):
248 sys.exit(1)
249
250 def delete_archive_by_name(self, container_id, archive_name):
251 self.containers_config.update_archive_install_status(container_id, archive_name, 'removing')
252 if LibertineContainer(container_id).configure_command('delete-archive', archive_name) is not 0:
253 return False
254 self.containers_config.delete_container_archive(container_id, archive_name)
255 return True
256
257 def configure(self, args):
258 container_id = self.containers_config.check_container_id(args.id)
259
260 container = LibertineContainer(container_id)
261
262 if args.multiarch and libertine.utils.get_host_architecture() == 'amd64':
263 multiarch = 'disabled'
264 if args.multiarch == 'enable':
265 multiarch = 'enabled'
266
267 current_multiarch = self.containers_config.get_container_multiarch_support(container_id)
268 if current_multiarch == multiarch:
269 print("i386 multiarch support is already %s" % multiarch)
270 sys.exit(1)
271
272 if container.configure_command('multiarch', args.multiarch) is not 0:
273 sys.exit(1)
274
275 self.containers_config.update_container_multiarch_support(container_id, multiarch)
276
277 elif args.add_archive:
278 if self.containers_config.archive_exists(container_id, args.add_archive):
279 print("%s already added in container." % args.add_archive)
280 sys.exit(1)
281
282 self.containers_config.add_container_archive(container_id, args.add_archive)
283 self.containers_config.update_archive_install_status(container_id, args.add_archive, 'installing')
284 if container.configure_command('add-archive', args.add_archive) is not 0:
285 self.containers_config.delete_container_archive(container_id, args.add_archive)
286 sys.exit(1)
287
288 self.containers_config.update_archive_install_status(container_id, args.add_archive, 'installed')
289
290 elif args.delete_archive:
291 if not self.containers_config.archive_exists(container_id, args.delete_archive):
292 print("%s is not added in container." % args.delete_archive)
293 sys.exit(1)
294
295 if not self.delete_archive_by_name(container_id, args.delete_archive):
296 sys.exit(1)
297
298 def merge(self, args):
299 self.containers_config.merge_container_config_files(args.file)
300
301 def fix_integrity(self, args):
302 for container in self.containers_config.container_list['containerList']:
303 if container['installStatus'] != 'ready':
304 self.destroy_container_by_id(container['id'])
305 continue
306 LibertineContainer(container['id']).exec_command('dpkg --configure -a')
307
308 for package in container['installedApps']:
309 if package['appStatus'] != 'installed':
310 self.remove_package_by_name(container['id'], package['packageName'])
311
312 if 'extraArchives' in container:
313 for archive in container['extraArchives']:
314 if archive['archiveStatus'] != 'installed':
315 self.delete_archive_by_name(container['id'], archive['archiveName'])
316
317 def set_default(self, args):
318 if args.clear:
319 self.containers_config.clear_default_container_id(True)
320 sys.exit(0)
321
322 container_id = self.containers_config.check_container_id(args.id)
323
324 self.containers_config.set_default_container_id(container_id, True)
651325
652326
653if __name__ == '__main__':327if __name__ == '__main__':
@@ -657,6 +331,8 @@
657 print("Please do not run %s using sudo" % parser.prog)331 print("Please do not run %s using sudo" % parser.prog)
658 sys.exit(1)332 sys.exit(1)
659333
334 container_manager = LibertineContainerManager()
335
660 parser.add_argument('-q', '--quiet',336 parser.add_argument('-q', '--quiet',
661 action='store_const', dest='verbosity', const=0,337 action='store_const', dest='verbosity', const=0,
662 help=('do not print status updates on stdout'))338 help=('do not print status updates on stdout'))
@@ -696,7 +372,7 @@
696 '--password',372 '--password',
697 help=("Pass in the user's password when creating an LXC container. This "373 help=("Pass in the user's password when creating an LXC container. This "
698 "is intended for testing only and is very insecure."))374 "is intended for testing only and is very insecure."))
699 parser_create.set_defaults(func=create)375 parser_create.set_defaults(func=container_manager.create)
700376
701 # Handle the destroy command and its options377 # Handle the destroy command and its options
702 parser_destroy = subparsers.add_parser(378 parser_destroy = subparsers.add_parser(
@@ -705,7 +381,7 @@
705 parser_destroy.add_argument(381 parser_destroy.add_argument(
706 '-i', '--id',382 '-i', '--id',
707 help=("Container identifier. Default container is used if omitted."))383 help=("Container identifier. Default container is used if omitted."))
708 parser_destroy.set_defaults(func=destroy)384 parser_destroy.set_defaults(func=container_manager.destroy)
709385
710 # Handle the install-package command and its options386 # Handle the install-package command and its options
711 parser_install = subparsers.add_parser(387 parser_install = subparsers.add_parser(
@@ -721,7 +397,7 @@
721 parser_install.add_argument(397 parser_install.add_argument(
722 '-r', '--readline', action='store_true',398 '-r', '--readline', action='store_true',
723 help=("Readline mode. Use text-based frontend during debconf interactions."))399 help=("Readline mode. Use text-based frontend during debconf interactions."))
724 parser_install.set_defaults(func=install_package)400 parser_install.set_defaults(func=container_manager.install_package)
725401
726 # Handle the remove-package command and its options402 # Handle the remove-package command and its options
727 parser_remove = subparsers.add_parser(403 parser_remove = subparsers.add_parser(
@@ -737,7 +413,7 @@
737 parser_remove.add_argument(413 parser_remove.add_argument(
738 '-r', '--readline', action='store_true',414 '-r', '--readline', action='store_true',
739 help=("Readline mode. Use text-based frontend during debconf interactions."))415 help=("Readline mode. Use text-based frontend during debconf interactions."))
740 parser_remove.set_defaults(func=remove_package)416 parser_remove.set_defaults(func=container_manager.remove_package)
741417
742 # Handle the search-cache command and its options418 # Handle the search-cache command and its options
743 parser_search = subparsers.add_parser(419 parser_search = subparsers.add_parser(
@@ -750,7 +426,7 @@
750 parser_search.add_argument(426 parser_search.add_argument(
751 '-i', '--id',427 '-i', '--id',
752 help=("Container identifier. Default container is used if omitted."))428 help=("Container identifier. Default container is used if omitted."))
753 parser_search.set_defaults(func=search_cache)429 parser_search.set_defaults(func=container_manager.search_cache)
754430
755 # Handle the update command and its options431 # Handle the update command and its options
756 parser_update = subparsers.add_parser(432 parser_update = subparsers.add_parser(
@@ -759,13 +435,13 @@
759 parser_update.add_argument(435 parser_update.add_argument(
760 '-i', '--id',436 '-i', '--id',
761 help=("Container identifier. Default container is used if omitted."))437 help=("Container identifier. Default container is used if omitted."))
762 parser_update.set_defaults(func=update)438 parser_update.set_defaults(func=container_manager.update)
763439
764 # Handle the list command440 # Handle the list command
765 parser_list = subparsers.add_parser(441 parser_list = subparsers.add_parser(
766 "list",442 "list",
767 help=("List all Libertine containers."))443 help=("List all Libertine containers."))
768 parser_list.set_defaults(func=list)444 parser_list.set_defaults(func=container_manager.list)
769445
770 # Handle the list-apps command and its options446 # Handle the list-apps command and its options
771 parser_list_apps = subparsers.add_parser(447 parser_list_apps = subparsers.add_parser(
@@ -778,7 +454,7 @@
778 '-j', '--json',454 '-j', '--json',
779 action='store_true',455 action='store_true',
780 help=("use JSON output format."))456 help=("use JSON output format."))
781 parser_list_apps.set_defaults(func=list_apps)457 parser_list_apps.set_defaults(func=container_manager.list_apps)
782458
783 # Handle the execute command and it's options459 # Handle the execute command and it's options
784 parser_exec = subparsers.add_parser(460 parser_exec = subparsers.add_parser(
@@ -791,7 +467,7 @@
791 parser_exec.add_argument(467 parser_exec.add_argument(
792 '-c', '--command',468 '-c', '--command',
793 help=("The command to run in the specified container."))469 help=("The command to run in the specified container."))
794 parser_exec.set_defaults(func=exec)470 parser_exec.set_defaults(func=container_manager.exec)
795471
796 # Handle the configure command and it's options472 # Handle the configure command and it's options
797 parser_configure = subparsers.add_parser(473 parser_configure = subparsers.add_parser(
@@ -816,7 +492,7 @@
816 metavar='Archive name',492 metavar='Archive name',
817 help=("Deletes an existing archive (PPA) in the specified Libertine container. "493 help=("Deletes an existing archive (PPA) in the specified Libertine container. "
818 "Needs to be in the form of \"ppa:user/ppa-name\"."))494 "Needs to be in the form of \"ppa:user/ppa-name\"."))
819 parser_configure.set_defaults(func=configure)495 parser_configure.set_defaults(func=container_manager.configure)
820496
821 # Handle merging another ContainersConfig.json file into the main ContainersConfig.json file497 # Handle merging another ContainersConfig.json file into the main ContainersConfig.json file
822 parser_merge = subparsers.add_parser(498 parser_merge = subparsers.add_parser(
@@ -825,13 +501,13 @@
825 parser_merge.add_argument(501 parser_merge.add_argument(
826 '-f', '--file',502 '-f', '--file',
827 required=True)503 required=True)
828 parser_merge.set_defaults(func=merge)504 parser_merge.set_defaults(func=container_manager.merge)
829505
830 # Indiscriminately destroy containers, packages, and archives which are not fully installed506 # Indiscriminately destroy containers, packages, and archives which are not fully installed
831 parser_integrity = subparsers.add_parser(507 parser_integrity = subparsers.add_parser(
832 'fix-integrity',508 'fix-integrity',
833 add_help=False)509 add_help=False)
834 parser_integrity.set_defaults(func=fix_integrity)510 parser_integrity.set_defaults(func=container_manager.fix_integrity)
835511
836 # Set the default container in ContainersConfig512 # Set the default container in ContainersConfig
837 parser_default = subparsers.add_parser(513 parser_default = subparsers.add_parser(
@@ -844,7 +520,7 @@
844 parser_default.add_argument(520 parser_default.add_argument(
845 '-c', '--clear', action='store_true',521 '-c', '--clear', action='store_true',
846 help=("Clear the default container."))522 help=("Clear the default container."))
847 parser_default.set_defaults(func=set_default)523 parser_default.set_defaults(func=container_manager.set_default)
848524
849 # Actually parse the args525 # Actually parse the args
850 args = parser.parse_args()526 args = parser.parse_args()

Subscribers

People subscribed via source and target branches