Merge lp:~larryprice/libertine/libertined-output into lp:libertine

Proposed by Larry Price on 2017-04-03
Status: Needs review
Proposed branch: lp:~larryprice/libertine/libertined-output
Merge into: lp:libertine
Diff against target: 1602 lines (+380/-258)
37 files modified
python/libertine/Libertine.py (+3/-4)
python/libertine/LxdContainer.py (+4/-3)
python/libertine/service/apt.py (+0/-1)
python/libertine/service/container.py (+22/-52)
python/libertine/service/download.py (+17/-21)
python/libertine/service/operations.py (+8/-8)
python/libertine/service/operations_monitor.py (+4/-0)
python/libertine/service/output_redirector.py (+67/-0)
python/libertine/service/task_dispatcher.py (+14/-26)
python/libertine/service/task_dispatcher_base.py (+49/-0)
python/libertine/service/tasks/app_info_task.py (+10/-8)
python/libertine/service/tasks/base_task.py (+51/-23)
python/libertine/service/tasks/container_info_task.py (+2/-2)
python/libertine/service/tasks/create_task.py (+13/-2)
python/libertine/service/tasks/destroy_task.py (+10/-9)
python/libertine/service/tasks/install_task.py (+26/-11)
python/libertine/service/tasks/list_app_ids_task.py (+2/-2)
python/libertine/service/tasks/list_task.py (+2/-2)
python/libertine/service/tasks/remove_task.py (+4/-3)
python/libertine/service/tasks/search_task.py (+11/-5)
python/libertine/service/tasks/update_task.py (+17/-4)
tests/integration/CMakeLists.txt (+2/-2)
tests/integration/test_libertine_service.py (+1/-0)
tests/unit/service/CMakeLists.txt (+1/-1)
tests/unit/service/tasks/test_app_info_task.py (+0/-2)
tests/unit/service/tasks/test_container_info_task.py (+0/-1)
tests/unit/service/tasks/test_create_task.py (+0/-10)
tests/unit/service/tasks/test_destroy_task.py (+0/-3)
tests/unit/service/tasks/test_install_task.py (+0/-3)
tests/unit/service/tasks/test_list_app_ids_task.py (+0/-2)
tests/unit/service/tasks/test_list_task.py (+0/-1)
tests/unit/service/tasks/test_remove_task.py (+0/-3)
tests/unit/service/tasks/test_search_task.py (+0/-1)
tests/unit/service/tasks/test_update_task.py (+0/-3)
tests/unit/service/test_container.py (+30/-30)
tests/unit/service/test_task_dispatcher.py (+10/-9)
tools/libertined (+0/-1)
To merge this branch: bzr merge lp:~larryprice/libertine/libertined-output
Reviewer Review Type Date Requested Status
Libertine CI Bot continuous-integration 2017-04-03 Needs Fixing on 2017-04-07
Libertine Developers 2017-04-03 Pending
Review via email: mp+321754@code.launchpad.net

This proposal supersedes a proposal from 2017-03-20.

Commit message

Forward task output from libertined to d-bus clients.

Description of the change

Forward task output from libertined to d-bus clients.

To post a comment you must log in.
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Libertine CI Bot (libertine-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:468
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/487/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/883
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/727
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/727
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/727
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/727
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/893
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/884
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/884/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/884
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/884/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/884
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/884/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/884
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/884/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:471
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/504/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/909
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/745
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/745
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/745
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/745
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/920
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/909
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/909/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/909
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/909/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/909
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/909/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/909
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/909/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:472
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/513/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/923
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/759
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/759
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/759
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/759
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/934
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/923
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/923/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/923
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/923/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/923
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/923/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/923
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/923/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
472. By Larry Price on 2017-04-07

merge

473. By Larry Price on 2017-04-07

chmod

Unmerged revisions

473. By Larry Price on 2017-04-07

chmod

472. By Larry Price on 2017-04-07

merge

471. By Larry Price on 2017-04-03

undoing po changes

470. By Larry Price on 2017-04-03

fixing test

469. By Larry Price on 2017-04-03

another merge attempt

468. By Larry Price on 2017-03-21

ok up cleanup cycle in test

467. By Larry Price on 2017-03-21

use XDG_DATA_HOME instead of HOME in OutputRedirector

466. By Larry Price on 2017-03-21

merge

465. By Larry Price on 2017-03-21

make dir tree if not exist

464. By Larry Price on 2017-03-20

undo accidents

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'python/libertine/Libertine.py'
2--- python/libertine/Libertine.py 2017-03-23 19:23:20 +0000
3+++ python/libertine/Libertine.py 2017-04-07 16:34:30 +0000
4@@ -258,12 +258,14 @@
5
6 return ret
7
8- def remove_package(self, package_name):
9+ def remove_package(self, package_name, no_dialog=False):
10 """
11 Removes a package from the container.
12
13 :param package_name: The name of the package to be removed.
14 """
15+ if no_dialog:
16+ os.environ['DEBIAN_FRONTEND'] = 'teletype'
17 if self.run_in_container(_apt_command_prefix() + " purge '" + package_name + "'") != 0:
18 return False
19 return self.run_in_container(_apt_command_prefix() + "autoremove --purge") == 0
20@@ -478,9 +480,6 @@
21 """
22 try:
23 with ContainerRunning(self.container):
24- if no_dialog:
25- os.environ['DEBIAN_FRONTEND'] = 'teletype'
26-
27 self.containers_config.update_container_install_status(self.container_id, "removing packages")
28 retval = self.container.remove_package(package_name)
29
30
31=== modified file 'python/libertine/LxdContainer.py'
32--- python/libertine/LxdContainer.py 2017-03-23 19:23:20 +0000
33+++ python/libertine/LxdContainer.py 2017-04-07 16:34:30 +0000
34@@ -112,7 +112,8 @@
35 def lxd_container(client, container_id):
36 try:
37 return client.containers.get(container_id)
38- except pylxd.exceptions.LXDAPIException:
39+ except pylxd.exceptions.LXDAPIException as e:
40+ utils.get_logger().error(str(e))
41 return None
42
43
44@@ -458,8 +459,8 @@
45 _add_local_files_for_ual(self._container)
46 return ret
47
48- def remove_package(self, package_name):
49- ret = super().remove_package(package_name)
50+ def remove_package(self, package_name, no_dialog=False):
51+ ret = super().remove_package(package_name, no_dialog)
52 _remove_local_files_for_ual(self._container)
53 return ret
54
55
56=== modified file 'python/libertine/service/apt.py'
57--- python/libertine/service/apt.py 2017-01-24 18:00:57 +0000
58+++ python/libertine/service/apt.py 2017-04-07 16:34:30 +0000
59@@ -54,7 +54,6 @@
60 app_data["summary"] = app.versions[0].summary
61 app_data["website"] = app.versions[0].homepage
62 app_data["description"] = app.versions[0].description
63- app_data["package"] = app.name
64
65 return app_data
66
67
68=== modified file 'python/libertine/service/container.py'
69--- python/libertine/service/container.py 2017-03-23 19:23:20 +0000
70+++ python/libertine/service/container.py 2017-04-07 16:34:30 +0000
71@@ -12,24 +12,23 @@
72 # You should have received a copy of the GNU General Public License
73 # along with this program. If not, see <http://www.gnu.org/licenses/>.
74
75+
76+from libertine import utils
77+from libertine.service.task_dispatcher_base import TaskDispatcherBase
78 from libertine.service.tasks import *
79-from libertine import utils
80-from threading import Lock
81+from multiprocessing import Lock
82
83 if not utils.is_snap_environment():
84 from libertine.service import apt
85
86
87-class Container(object):
88+class Container(TaskDispatcherBase):
89 def __init__(self, container_id, config, monitor, client, callback):
90+ super().__init__(monitor, client)
91 self._id = container_id
92 self._config = config
93- self._monitor = monitor
94- self._client = client
95 self._callback = callback
96-
97 self._lock = Lock()
98- self._tasks = []
99
100 if utils.is_snap_environment():
101 utils.get_logger().warning(utils._("Using AptCache not currently supported in snap environment"))
102@@ -37,13 +36,9 @@
103 else:
104 self._cache = apt.AptCache(self.id)
105
106- def _cleanup_task(self, task):
107- utils.get_logger().debug("cleaning up tasks for container '%s'" % self.id)
108-
109- if task in self._tasks:
110- self._tasks.remove(task)
111-
112- if len(self._tasks) == 0:
113+ def _cleanup(self):
114+ super()._cleanup()
115+ if not self._tasks:
116 self._callback(self)
117
118 @property
119@@ -54,7 +49,7 @@
120 def tasks(self):
121 return [task.id for task in self._tasks if task.running]
122
123- def install(self, package_name):
124+ def install(self, package_name, update_cache):
125 utils.get_logger().debug("Install package '%s' from container '%s'" % (package_name, self.id))
126
127 tasks = [t for t in self._tasks if t.matches(package_name, InstallTask) and t.running]
128@@ -62,10 +57,8 @@
129 utils.get_logger().debug("Install already in progress for '%s':'%s'" % (package_name, self.id))
130 return tasks[0].id
131
132- task = InstallTask(package_name, self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
133- self._tasks.append(task)
134- task.start()
135- return task.id
136+ return self._add_task(InstallTask(package_name, self.id, update_cache, self._config,
137+ self._lock, self._monitor, self._client))
138
139 def remove(self, package_name):
140 utils.get_logger().debug("Remove package '%s' from container '%s'" % (package_name, self.id))
141@@ -75,10 +68,7 @@
142 utils.get_logger().debug("Remove already in progress for '%s':'%s'" % (package_name, self.id))
143 return tasks[0].id
144
145- task = RemoveTask(package_name, self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
146- self._tasks.append(task)
147- task.start()
148- return task.id
149+ return self._add_task(RemoveTask(package_name, self.id, self._config, self._lock, self._monitor, self._client))
150
151 def create(self, container_name, distro, container_type, enable_multiarch):
152 utils.get_logger().debug("Create container with ID '%s'" % self.id)
153@@ -88,13 +78,10 @@
154 utils.get_logger().debug("Create already in progress for '%s'" % self.id)
155 return tasks[0].id
156
157- task = CreateTask(self.id, container_name, distro, container_type, enable_multiarch,
158- self._config, self._lock, self._monitor, self._client, self._cleanup_task)
159- self._tasks.append(task)
160- task.start()
161- return task.id
162+ return self._add_task(CreateTask(self.id, container_name, distro, container_type, enable_multiarch,
163+ self._config, self._lock, self._monitor, self._client))
164
165- def destroy(self):
166+ def destroy(self, force):
167 utils.get_logger().debug("Destroy container with ID '%s'" % self.id)
168
169 tasks = [t for t in self._tasks if t.matches(self.id, DestroyTask) and t.running]
170@@ -102,10 +89,7 @@
171 utils.get_logger().debug("Destroy already in progress for '%s'" % self.id)
172 return tasks[0].id
173
174- task = DestroyTask(self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
175- self._tasks.append(task)
176- task.start()
177- return task.id
178+ return self._add_task(DestroyTask(self.id, self._config, force, self._lock, self._monitor, self._client))
179
180 def update(self):
181 utils.get_logger().debug("Update container with ID '%s'" % self.id)
182@@ -115,21 +99,14 @@
183 utils.get_logger().debug("Update already in progress for '%s'" % self.id)
184 return tasks[0].id
185
186- task = UpdateTask(self.id, self._config, self._lock, self._monitor, self._client, self._cleanup_task)
187- self._tasks.append(task)
188- task.start()
189- return task.id
190+ return self._add_task(UpdateTask(self.id, self._config, self._lock, self._monitor, self._client))
191
192 # Tasks which don't require starting/stopping the container
193
194 def list_app_ids(self):
195 utils.get_logger().debug("List all app ids in container '%s'" % self.id)
196
197- task = ListAppIdsTask(self.id, self._config, self._monitor, self._client, self._cleanup_task)
198-
199- self._tasks.append(task)
200- task.start()
201- return task.id
202+ return self._add_task(ListAppIdsTask(self.id, self._config, self._monitor, self._client))
203
204 def search(self, query):
205 utils.get_logger().debug("search container '%s' for package '%s'" % (self.id, query))
206@@ -137,11 +114,7 @@
207 if utils.is_snap_environment():
208 raise Exception("This operation is not currently supported within the snap")
209
210- task = SearchTask(self.id, self._cache, query, self._monitor, self._cleanup_task)
211- self._tasks.append(task)
212- task.start()
213-
214- return task.id
215+ return self._add_task(SearchTask(self.id, self._cache, query, self._config, self._monitor, self._client))
216
217 def app_info(self, package_name):
218 utils.get_logger().debug("get info for package '%s' in container '%s'" % (package_name, self.id))
219@@ -150,8 +123,5 @@
220 raise Exception("This operation is not currently supported within the snap")
221
222 related_task_ids = [t.id for t in self._tasks if t.package == package_name and t.running]
223- task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._monitor, self._cleanup_task)
224-
225- self._tasks.append(task)
226- task.start()
227- return task.id
228+ return self._add_task(AppInfoTask(self.id, self._cache, package_name, related_task_ids,
229+ self._config, self._monitor, self._client))
230
231=== modified file 'python/libertine/service/download.py'
232--- python/libertine/service/download.py 2017-03-07 18:38:05 +0000
233+++ python/libertine/service/download.py 2017-04-07 16:34:30 +0000
234@@ -14,7 +14,7 @@
235
236
237 import dbus.service
238-import threading
239+import multiprocessing
240
241 from . import constants
242 from libertine import utils
243@@ -23,39 +23,35 @@
244
245 class Download(dbus.service.Object):
246 def __init__(self, connection, id):
247- self._finished = False
248- self._result = ''
249- self._error = ''
250+ self._finished = multiprocessing.Event()
251+ self._result = multiprocessing.SimpleQueue()
252+ self._error = multiprocessing.SimpleQueue()
253 dbus.service.Object.__init__(self, conn=connection, object_path=(constants.DOWNLOAD_OBJECT % id))
254
255- # Disabled until something requires the Download interface
256- # self.emit_processing()
257-
258- # This is currently how services using the Ubuntu SDK to show progress
259- # determine whether or not an operation is running.
260- def emit_processing(self):
261- if not self.done:
262- self.processing(self.id)
263- threading.Timer(0.5, self.emit_processing).start()
264-
265 @property
266 def id(self):
267 return self._object_path
268
269 @property
270 def done(self):
271- return self._finished
272+ return self._finished.is_set()
273
274 @property
275 def result(self):
276- return self._result.strip()
277+ if self._result.empty():
278+ return ''
279+
280+ return self._result.get()
281
282 @property
283 def last_error(self):
284- return self._error
285+ if self._error.empty():
286+ return ''
287+
288+ return self._error.get()
289
290 def data(self, message):
291- self._result += message + '\n'
292+ self._result.put(message)
293
294 # Signals to satisfy the download interface
295
296@@ -66,7 +62,7 @@
297 @dbus.service.signal(constants.DOWNLOAD_INTERFACE, signature='o')
298 def finished(self, path):
299 utils.get_logger().debug("emit finished('%s')" % path)
300- self._finished = True
301+ self._finished.set()
302
303 @dbus.service.signal(constants.DOWNLOAD_INTERFACE)
304 def progress(self, received, total):
305@@ -75,5 +71,5 @@
306 @dbus.service.signal(constants.DOWNLOAD_INTERFACE, signature='s')
307 def error(self, message):
308 utils.get_logger().error("emit error(%s)" % message)
309- self._error = message
310- self._finished = True
311+ self._error.put(message)
312+ self._finished.set()
313
314=== modified file 'python/libertine/service/operations.py'
315--- python/libertine/service/operations.py 2017-03-09 14:40:58 +0000
316+++ python/libertine/service/operations.py 2017-04-07 16:34:30 +0000
317@@ -72,11 +72,11 @@
318 return self._dispatcher.create(container_id, container_name, distro, container_type, enable_multiarch)
319
320 @dbus.service.method(constants.OPERATIONS_INTERFACE,
321- in_signature='s',
322+ in_signature='sb',
323 out_signature='o')
324- def destroy(self, container_id):
325- utils.get_logger().debug("destroy('{}')".format(container_id))
326- return self._dispatcher.destroy(container_id)
327+ def destroy(self, container_id, force=False):
328+ utils.get_logger().debug("destroy('{}', {})".format(container_id, force))
329+ return self._dispatcher.destroy(container_id, force)
330
331 @dbus.service.method(constants.OPERATIONS_INTERFACE,
332 in_signature='s',
333@@ -86,11 +86,11 @@
334 return self._dispatcher.update(container_id)
335
336 @dbus.service.method(constants.OPERATIONS_INTERFACE,
337- in_signature='ss',
338+ in_signature='ssb',
339 out_signature='o')
340- def install(self, container_id, package_name):
341- utils.get_logger().debug("install('%s', '%s')" % (container_id, package_name))
342- return self._dispatcher.install(container_id, package_name)
343+ def install(self, container_id, package_name, update_cache=False):
344+ utils.get_logger().debug("install('{}', '{}', '{}')".format(container_id, package_name, update_cache))
345+ return self._dispatcher.install(container_id, package_name, update_cache)
346
347 @dbus.service.method(constants.OPERATIONS_INTERFACE,
348 in_signature='ss',
349
350=== modified file 'python/libertine/service/operations_monitor.py'
351--- python/libertine/service/operations_monitor.py 2017-03-27 20:06:39 +0000
352+++ python/libertine/service/operations_monitor.py 2017-04-07 16:34:30 +0000
353@@ -68,6 +68,10 @@
354 if op:
355 op.data(message)
356
357+ @dbus.service.signal(constants.OPERATIONS_MONITOR_INTERFACE, signature='os')
358+ def output(self, path, message):
359+ utils.get_logger().debug(message)
360+
361 @dbus.service.method(constants.OPERATIONS_MONITOR_INTERFACE, in_signature='o', out_signature='b')
362 def running(self, path):
363 op = self._operation(path)
364
365=== added file 'python/libertine/service/output_redirector.py'
366--- python/libertine/service/output_redirector.py 1970-01-01 00:00:00 +0000
367+++ python/libertine/service/output_redirector.py 2017-04-07 16:34:30 +0000
368@@ -0,0 +1,67 @@
369+# Copyright 2017 Canonical Ltd.
370+#
371+# This program is free software: you can redistribute it and/or modify
372+# it under the terms of the GNU General Public License as published by
373+# the Free Software Foundation; version 3 of the License.
374+#
375+# This program is distributed in the hope that it will be useful,
376+# but WITHOUT ANY WARRANTY; without even the implied warranty of
377+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
378+# GNU General Public License for more details.
379+#
380+# You should have received a copy of the GNU General Public License
381+# along with this program. If not, see <http://www.gnu.org/licenses/>.
382+
383+
384+import os
385+import sys
386+
387+from libertine import utils
388+
389+
390+class OutputRedirector(object):
391+ def __init__(self, ident, cleanup=True):
392+ self.cleanup = cleanup
393+
394+ if utils.is_snap_environment():
395+ self.cache_path = '%s/.cache/libertined' % os.environ['SNAP_USER_COMMON']
396+ else:
397+ self.cache_path = os.path.join(os.getenv(('XDG_DATA_HOME'), os.getenv('HOME')), '.cache/libertined')
398+
399+ self.path = '{}/{}.log'.format(self.cache_path, ident)
400+ self._output_file = None
401+ self._copied_stdout = None
402+ self._copied_stderr = None
403+
404+ def _fileno(self, file_or_fd):
405+ return getattr(file_or_fd, 'fileno', lambda: file_or_fd)()
406+
407+ def _do_redirect(self, stream):
408+ fd = self._fileno(stream)
409+ copied_stream = os.fdopen(os.dup(fd), 'wb')
410+ stream.flush()
411+ os.dup2(self._fileno(self._output_file), fd)
412+ return copied_stream, fd
413+
414+ def _undo_redirect(self, stream, stream_fd, copied_stream):
415+ stream.flush()
416+ os.dup2(copied_stream.fileno(), stream_fd)
417+ copied_stream.close()
418+
419+ def __enter__(self):
420+ os.makedirs(self.cache_path, exist_ok=True)
421+ self._output_file = open(self.path, 'w')
422+ self._copied_stdout, self.stdout_fd = self._do_redirect(sys.stdout)
423+ self._copied_stderr, self.stderr_fd = self._do_redirect(sys.stderr)
424+
425+ return self
426+
427+ def __exit__(self, type, value, tb):
428+ if self._copied_stdout and self.stdout_fd:
429+ self._undo_redirect(sys.stdout, self.stdout_fd, self._copied_stdout)
430+ if self._copied_stderr and self.stderr_fd:
431+ self._undo_redirect(sys.stderr, self.stderr_fd, self._copied_stderr)
432+ if self._output_file:
433+ self._output_file.close()
434+ if self.cleanup and os.path.exists(self.path):
435+ os.remove(self.path)
436
437=== modified file 'python/libertine/service/task_dispatcher.py'
438--- python/libertine/service/task_dispatcher.py 2017-03-27 20:06:39 +0000
439+++ python/libertine/service/task_dispatcher.py 2017-04-07 16:34:30 +0000
440@@ -14,25 +14,20 @@
441
442
443 import libertine.ContainersConfig
444+
445+from libertine import utils
446 from libertine.service.container import Container
447+from libertine.service.task_dispatcher_base import TaskDispatcherBase
448 from libertine.service.tasks import *
449-from libertine import utils
450-
451-
452-class TaskDispatcher(object):
453+from multiprocessing import Lock
454+
455+
456+class TaskDispatcher(TaskDispatcherBase):
457 def __init__(self, monitor, client):
458- self._monitor = monitor
459- self._client = client
460+ super().__init__(monitor, client)
461 self._config = libertine.ContainersConfig.ContainersConfig()
462- self._containerless_tasks = []
463- self._tasks = []
464 self._containers = []
465
466- def _cleanup_task(self, task):
467- utils.get_logger().debug("cleaning up containerless task '%s'" % task.id)
468- if task in self._tasks:
469- self._tasks.remove(task)
470-
471 def _cleanup_container(self, container):
472 utils.get_logger().debug("cleaning up container '%s'" % container.id)
473 if container in self._containers:
474@@ -66,9 +61,9 @@
475 utils.get_logger().debug("dispatching app_info in container '%s' for package '%s'" % (container_id, app_id))
476 return self._find_or_create_container(container_id).app_info(app_id)
477
478- def install(self, container_id, package_name):
479+ def install(self, container_id, package_name, update_cache):
480 utils.get_logger().debug("dispatching install of package '%s' from container '%s'" % (package_name, container_id))
481- return self._find_or_create_container(container_id).install(package_name)
482+ return self._find_or_create_container(container_id).install(package_name, update_cache)
483
484 def remove(self, container_id, package_name):
485 utils.get_logger().debug("dispatching remove of package '%s' from container '%s'" % (package_name, container_id))
486@@ -78,9 +73,9 @@
487 utils.get_logger().debug("dispatching create of container '%s'" % container_id)
488 return self._find_or_create_container(container_id).create(container_name, distro, container_type, enable_multiarch)
489
490- def destroy(self, container_id):
491+ def destroy(self, container_id, force):
492 utils.get_logger().debug("dispatching destroy container '%s'" % container_id)
493- return self._find_or_create_container(container_id).destroy()
494+ return self._find_or_create_container(container_id).destroy(force)
495
496 def update(self, container_id):
497 utils.get_logger().debug("dispatching update container '%s'" % container_id)
498@@ -99,17 +94,10 @@
499 container = self._find_container(container_id)
500 if container is not None:
501 related_task_ids = container.tasks
502- task = ContainerInfoTask(container_id, related_task_ids, self._config, self._monitor, self._cleanup_task)
503- self._tasks.append(task)
504- task.start()
505
506- return task.id
507+ return self._add_task(ContainerInfoTask(container_id, related_task_ids, self._config, self._monitor))
508
509 def list(self):
510 utils.get_logger().debug("dispatching list all containers")
511
512- task = ListTask(self._config, self._monitor, self._cleanup_task)
513- self._tasks.append(task)
514- task.start()
515-
516- return task.id
517+ return self._add_task(ListTask(self._config, self._monitor))
518
519=== added file 'python/libertine/service/task_dispatcher_base.py'
520--- python/libertine/service/task_dispatcher_base.py 1970-01-01 00:00:00 +0000
521+++ python/libertine/service/task_dispatcher_base.py 2017-04-07 16:34:30 +0000
522@@ -0,0 +1,49 @@
523+# Copyright 2017 Canonical Ltd.
524+#
525+# This program is free software: you can redistribute it and/or modify
526+# it under the terms of the GNU General Public License as published by
527+# the Free Software Foundation; version 3 of the License.
528+#
529+# This program is distributed in the hope that it will be useful,
530+# but WITHOUT ANY WARRANTY; without even the implied warranty of
531+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
532+# GNU General Public License for more details.
533+#
534+# You should have received a copy of the GNU General Public License
535+# along with this program. If not, see <http://www.gnu.org/licenses/>.
536+
537+
538+import multiprocessing
539+import os
540+
541+from libertine import utils
542+from threading import Timer
543+
544+
545+class TaskDispatcherBase(object):
546+ def __init__(self, monitor, client):
547+ self._monitor = monitor
548+ self._client = client
549+ self._tasks = []
550+
551+ self._cleanup_cycle = 1
552+ if os.getenv("LIBERTINED_TESTING", False):
553+ self._cleanup_cycle = 0.1
554+
555+ def _cleanup(self):
556+ for task in [task for task in self._tasks if task.should_delete]:
557+ utils.get_logger().debug("Cleaning up task '{}'".format(task.id))
558+ task.thread.join()
559+ self._monitor.remove_from_connection(task.id)
560+ self._tasks.remove(task)
561+
562+ if len(self._tasks) > 0:
563+ Timer(self._cleanup_cycle, self._cleanup).start()
564+
565+ def _add_task(self, task):
566+ self._tasks.append(task)
567+ task.start()
568+ if len(self._tasks) == 1:
569+ Timer(self._cleanup_cycle, self._cleanup).start()
570+
571+ return task.id
572
573=== modified file 'python/libertine/service/tasks/app_info_task.py'
574--- python/libertine/service/tasks/app_info_task.py 2017-03-07 20:56:42 +0000
575+++ python/libertine/service/tasks/app_info_task.py 2017-04-07 16:34:30 +0000
576@@ -13,22 +13,24 @@
577 # along with this program. If not, see <http://www.gnu.org/licenses/>.
578
579
580-from .base_task import BaseTask
581+from .base_task import ContainerBaseTask
582 from libertine import utils
583
584
585-class AppInfoTask(BaseTask):
586- def __init__(self, container_id, cache, app_id, tasks, config, monitor, callback):
587- super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, callback=callback)
588+class AppInfoTask(ContainerBaseTask):
589+ def __init__(self, container_id, cache, app_id, tasks, config, monitor, client):
590+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, client=client)
591 self._cache = cache
592 self._app_id = app_id
593 self._tasks = tasks
594
595 def _run(self):
596- app = self._cache.app_info(self._app_id)
597- if app == {}:
598- self._error("Could not find app info for '%s' in container '%s'" % (self._app_id, self._container))
599- return
600+ app = {}
601+ if self._cache:
602+ app = self._cache.app_info(self._app_id)
603+ if app == {}:
604+ self._error("Could not find app info for '%s' in container '%s'" % (self._app_id, self._container))
605+ return
606
607 app['status'] = self._config.get_package_install_status(self._container, app['package']) or ''
608 app['task_ids'] = self._tasks
609
610=== modified file 'python/libertine/service/tasks/base_task.py'
611--- python/libertine/service/tasks/base_task.py 2017-03-27 20:06:39 +0000
612+++ python/libertine/service/tasks/base_task.py 2017-04-07 16:34:30 +0000
613@@ -13,9 +13,13 @@
614 # along with this program. If not, see <http://www.gnu.org/licenses/>.
615
616
617-import threading
618+import multiprocessing
619+import os
620+import time
621
622 from abc import ABCMeta, abstractmethod
623+from libertine import utils
624+from libertine.service import output_redirector
625
626
627 class BaseTask(metaclass=ABCMeta):
628@@ -25,14 +29,14 @@
629 in a separate thread. Override _before to implement pre-execution actions
630 without locking; if _before returns False, _run will not be executed.
631 """
632- def __init__(self, lock, container_id, config, monitor, callback):
633+ def __init__(self, lock, container_id, config, monitor):
634 self._lock = lock
635 self._container = container_id
636 self._config = config
637- self._callback = callback
638+ self._finished_at = multiprocessing.SimpleQueue()
639 self._monitor = monitor
640 self._operation_id = None
641- self._instant_callback = False # for testing
642+ self._delete_at = None
643
644 def matches(self, container, klass):
645 return self._container == container and self.__class__ == klass
646@@ -53,38 +57,62 @@
647 def running(self):
648 return not self._monitor.done(self._operation_id)
649
650- def _delayed_callback(self):
651- if self._instant_callback:
652- self._callback(self)
653- else:
654- threading.Timer(10, lambda: (self._monitor.remove_from_connection(self._operation_id), self._callback(self))).start()
655+ @property
656+ def should_delete(self):
657+ if not self._finished_at.empty():
658+ self._delete_at = self._finished_at.get()
659+ if not os.getenv("LIBERTINED_TESTING"):
660+ self._delete_at += 5
661+
662+ if self._delete_at:
663+ return self._delete_at < time.time()
664+
665+ return False
666+
667+ def _finish(self):
668+ self._finished_at.put(time.time())
669
670 def start(self):
671 self._operation_id = self._monitor.new_operation()
672- thread = threading.Thread(target=self.run)
673- thread.start()
674- return thread
675+ self.thread = multiprocessing.Process(target=self.run)
676+ self.thread.start()
677+ return self.thread
678+
679+ def watch_file(self, finished, path):
680+ with open(path, 'rb') as thefile:
681+ thefile.seek(0, 2)
682+ while not finished.is_set():
683+ finished.wait(0.1)
684+ line = thefile.readline().decode('utf-8').rstrip()
685+ while line:
686+ self._monitor.output(self._operation_id, message)
687+ line = thefile.readline().decode('utf-8').rstrip()
688
689 def run(self):
690 self._refresh_database()
691
692 if not self._before():
693 self._monitor.finished(self._operation_id)
694- self._delayed_callback()
695+ self._finish()
696 return
697
698- if self._lock is not None:
699- with self._lock:
700- self._refresh_database(False)
701+ with output_redirector.OutputRedirector(self._operation_id.split("/")[-1]) as redirector:
702+ end_watch = multiprocessing.Event()
703+ multiprocessing.Process(target=self.watch_file, args=(end_watch, redirector.path)).start()
704+ if self._lock is not None:
705+ with self._lock:
706+ self._refresh_database(False)
707+ self._run()
708+ else:
709+ self._refresh_database()
710 self._run()
711- else:
712- self._refresh_database()
713- self._run()
714+
715+ end_watch.set()
716
717 if self.running:
718- self._finished()
719+ self._monitor.finished(self._operation_id)
720
721- self._delayed_callback()
722+ self._finish()
723
724 def _refresh_database(self, require_lock=True):
725 if self._config:
726@@ -112,6 +140,6 @@
727
728
729 class ContainerBaseTask(BaseTask):
730- def __init__(self, lock, container_id, config, monitor, client, callback):
731- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
732+ def __init__(self, lock, container_id, config, monitor, client):
733+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor)
734 self._client = client
735
736=== modified file 'python/libertine/service/tasks/container_info_task.py'
737--- python/libertine/service/tasks/container_info_task.py 2017-03-06 19:50:12 +0000
738+++ python/libertine/service/tasks/container_info_task.py 2017-04-07 16:34:30 +0000
739@@ -20,8 +20,8 @@
740
741
742 class ContainerInfoTask(BaseTask):
743- def __init__(self, container_id, tasks, config, monitor, callback):
744- super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, callback=callback)
745+ def __init__(self, container_id, tasks, config, monitor):
746+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor)
747 self._tasks = tasks
748
749 def _run(self):
750
751=== modified file 'python/libertine/service/tasks/create_task.py'
752--- python/libertine/service/tasks/create_task.py 2017-03-27 20:06:39 +0000
753+++ python/libertine/service/tasks/create_task.py 2017-04-07 16:34:30 +0000
754@@ -13,6 +13,8 @@
755 # along with this program. If not, see <http://www.gnu.org/licenses/>.
756
757
758+import re
759+
760 from .base_task import ContainerBaseTask
761 from libertine import LibertineContainer, utils
762 from libertine.HostInfo import HostInfo
763@@ -20,9 +22,9 @@
764
765 class CreateTask(ContainerBaseTask):
766 def __init__(self, container_id, container_name, distro, container_type, enable_multiarch,
767- config, lock, monitor, client, callback):
768+ config, lock, monitor, client):
769 super().__init__(lock=lock, container_id=container_id, config=config,
770- monitor=monitor, client=client, callback=callback)
771+ monitor=monitor, client=client)
772 self._name = container_name
773 self._distro = distro
774 self._type = container_type
775@@ -39,6 +41,7 @@
776 self._error("Creating container '%s' failed" % self._container)
777 else:
778 self._config.update_container_install_status(self._container, "ready")
779+ utils.refresh_libertine_scope()
780 self._finished()
781 except RuntimeError as e:
782 self._config.delete_container(self._container)
783@@ -50,6 +53,10 @@
784 self._error("Container '%s' already exists" % self._container)
785 return False
786
787+ if re.match("^[a-z0-9][a-z0-9+.-]+$", self._container) is None:
788+ self._error("Container id '%s' invalid. ID must be of form ([a-z0-9][a-z0-9+.-]+)." % self._container)
789+ return False
790+
791 info = HostInfo()
792 if not self._distro:
793 self._distro = info.get_host_distro_release()
794@@ -72,6 +79,10 @@
795
796 if self._multiarch:
797 self._config.update_container_multiarch_support(self._container, 'enabled')
798+ else:
799+ self._config.update_container_multiarch_support(self._container, 'disabled')
800+
801+ self._config.update_container_locale(self._container, info.get_host_locale())
802
803 self._config.update_container_install_status(self._container, 'installing')
804 return True
805
806=== modified file 'python/libertine/service/tasks/destroy_task.py'
807--- python/libertine/service/tasks/destroy_task.py 2017-03-27 20:06:39 +0000
808+++ python/libertine/service/tasks/destroy_task.py 2017-04-07 16:34:30 +0000
809@@ -18,27 +18,28 @@
810
811
812 class DestroyTask(ContainerBaseTask):
813- def __init__(self, container_id, config, lock, monitor, client, callback):
814+ def __init__(self, container_id, config, force, lock, monitor, client):
815 super().__init__(lock=lock, container_id=container_id, config=config,
816- monitor=monitor, client=client, callback=callback)
817+ monitor=monitor, client=client)
818+ self._force = force
819
820 def _run(self):
821 utils.get_logger().debug("Destroying container '%s'" % self._container)
822
823 container = LibertineContainer(self._container, self._config, self._client)
824- if not container.destroy_libertine_container():
825+ if not container.destroy_libertine_container(self._force):
826 self._error("Destroying container '%s' failed" % self._container)
827- self._config.update_container_install_status(self._container, "ready")
828+ self._config.update_container_install_status(self._container, self._fallback)
829 return
830
831+ self._config.update_container_install_status(self._container, "removed")
832 self._config.delete_container(self._container)
833 self._finished()
834
835+ utils.refresh_libertine_scope()
836+
837 def _before(self):
838- utils.get_logger().debug("CreateTask::_before")
839- if self._config._get_value_by_key(self._container, 'installStatus') != 'ready':
840- self._error("Container '%s' does not exist" % self._container)
841- return False
842-
843+ utils.get_logger().debug("DestroyTask::_before")
844+ self._fallback = self._config.get_container_install_status(self._container)
845 self._config.update_container_install_status(self._container, 'removing')
846 return True
847
848=== modified file 'python/libertine/service/tasks/install_task.py'
849--- python/libertine/service/tasks/install_task.py 2017-03-27 20:06:39 +0000
850+++ python/libertine/service/tasks/install_task.py 2017-04-07 16:34:30 +0000
851@@ -13,15 +13,19 @@
852 # along with this program. If not, see <http://www.gnu.org/licenses/>.
853
854
855+import os
856+
857 from .base_task import ContainerBaseTask
858 from libertine import LibertineContainer, utils
859
860
861 class InstallTask(ContainerBaseTask):
862- def __init__(self, package_name, container_id, config, lock, monitor, client, callback):
863+ def __init__(self, package_name, container_id, update_cache, config, lock, monitor, client):
864 super().__init__(lock=lock, container_id=container_id, config=config,
865- monitor=monitor, client=client, callback=callback)
866+ monitor=monitor, client=client)
867 self._package = package_name
868+ self._package_name = package_name
869+ self._update_cache = update_cache
870
871 def matches(self, package, klass):
872 return self._package == package and self.__class__ == klass
873@@ -33,19 +37,30 @@
874 def _run(self):
875 utils.get_logger().debug("Installing package '%s'" % self._package)
876 container = LibertineContainer(self._container, self._config, self._client)
877- if container.install_package(self._package):
878- self._config.update_package_install_status(self._container, self._package, "installed")
879+ if container.install_package(self._package, update_cache=self._update_cache, no_dialog=True):
880+ self._config.update_package_install_status(self._container, self._package_name, "installed")
881+ utils.refresh_libertine_scope()
882 self._finished()
883 else:
884- self._config.delete_package(self._container, self._package)
885+ self._config.delete_package(self._container, self._package_name)
886 self._error("Package installation failed for '%s'" % self._package)
887
888 def _before(self):
889 utils.get_logger().debug("InstallTask::_before")
890- if self._config.package_exists(self._container, self._package):
891- self._error("Package '%s' already exists, skipping install" % self._package)
892- return False
893+ is_debian_package = self._package.endswith('.deb')
894+ if is_debian_package:
895+ if os.path.exists(self._package):
896+ self._package_name = utils.get_deb_package_name(self._package)
897+ else:
898+ libertine.utils.get_logger().error("'%s' does not exist." % self._package)
899+ return False
900+
901+ if self._config.package_exists(self._container, self._package_name):
902+ if not is_debian_package:
903+ self._error("Package '%s' is already installed" % self._package_name)
904+ return False
905 else:
906- self._config.add_new_package(self._container, self._package)
907- self._config.update_package_install_status(self._container, self._package, "installing")
908- return True
909+ self._config.add_new_package(self._container, self._package_name)
910+
911+ self._config.update_package_install_status(self._container, self._package_name, "installing")
912+ return True
913
914=== modified file 'python/libertine/service/tasks/list_app_ids_task.py'
915--- python/libertine/service/tasks/list_app_ids_task.py 2017-03-16 19:59:08 +0000
916+++ python/libertine/service/tasks/list_app_ids_task.py 2017-04-07 16:34:30 +0000
917@@ -20,8 +20,8 @@
918
919
920 class ListAppIdsTask(ContainerBaseTask):
921- def __init__(self, container_id, config, monitor, client, callback):
922- super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, client=client, callback=callback)
923+ def __init__(self, container_id, config, monitor, client):
924+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, client=client)
925
926 def _run(self):
927 utils.get_logger().debug("Listing app ids from container '%s'" % self._container)
928
929=== modified file 'python/libertine/service/tasks/list_task.py'
930--- python/libertine/service/tasks/list_task.py 2017-03-27 20:06:39 +0000
931+++ python/libertine/service/tasks/list_task.py 2017-04-07 16:34:30 +0000
932@@ -20,8 +20,8 @@
933
934
935 class ListTask(BaseTask):
936- def __init__(self, config, monitor, callback):
937- super().__init__(lock=None, container_id=None, config=config, monitor=monitor, callback=callback)
938+ def __init__(self, config, monitor):
939+ super().__init__(lock=None, container_id=None, config=config, monitor=monitor)
940
941 def _run(self):
942 self._data(json.dumps(self._config.get_containers()))
943
944=== modified file 'python/libertine/service/tasks/remove_task.py'
945--- python/libertine/service/tasks/remove_task.py 2017-03-27 20:06:39 +0000
946+++ python/libertine/service/tasks/remove_task.py 2017-04-07 16:34:30 +0000
947@@ -18,8 +18,8 @@
948
949
950 class RemoveTask(ContainerBaseTask):
951- def __init__(self, package_name, container_id, config, lock, monitor, client, callback):
952- super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, client=client, callback=callback)
953+ def __init__(self, package_name, container_id, config, lock, monitor, client):
954+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, client=client)
955 self._package = package_name
956
957 def matches(self, package, klass):
958@@ -32,8 +32,9 @@
959 def _run(self):
960 utils.get_logger().debug("Removing package '%s'" % self._package)
961 container = LibertineContainer(self._container, self._config, self._client)
962- if container.remove_package(self._package):
963+ if container.remove_package(self._package, no_dialog=True):
964 self._config.delete_package(self._container, self._package)
965+ utils.refresh_libertine_scope()
966 self._finished()
967 else:
968 self._config.update_package_install_status(self._container, self._package, 'installed')
969
970=== modified file 'python/libertine/service/tasks/search_task.py'
971--- python/libertine/service/tasks/search_task.py 2017-03-07 18:38:05 +0000
972+++ python/libertine/service/tasks/search_task.py 2017-04-07 16:34:30 +0000
973@@ -13,15 +13,21 @@
974 # along with this program. If not, see <http://www.gnu.org/licenses/>.
975
976
977-from .base_task import BaseTask
978+from .base_task import ContainerBaseTask
979 from libertine import utils
980
981
982-class SearchTask(BaseTask):
983- def __init__(self, container_id, cache, query, monitor, callback):
984- super().__init__(lock=None, container_id=container_id, config=None, monitor=monitor, callback=callback)
985+class SearchTask(ContainerBaseTask):
986+ def __init__(self, container_id, cache, query, config, monitor, client):
987+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, client=client)
988 self._cache = cache
989 self._query = query
990
991 def _run(self):
992- self._data(str(self._cache.search(self._query)))
993+ if self._cache:
994+ self._data(str(self._cache.search(self._query)))
995+ else:
996+ container = LibertineContainer(self._container, self._config, self._client)
997+ if container.search_package_cache(self._query) is not 0:
998+ self._error("Search for '{}' in container '{}' exited with non-zero status"
999+ .format(self._container, self._query))
1000
1001=== modified file 'python/libertine/service/tasks/update_task.py'
1002--- python/libertine/service/tasks/update_task.py 2017-03-09 16:02:22 +0000
1003+++ python/libertine/service/tasks/update_task.py 2017-04-07 16:34:30 +0000
1004@@ -14,21 +14,34 @@
1005
1006
1007 from .base_task import ContainerBaseTask
1008-from libertine import LibertineContainer, utils
1009+from libertine import LibertineContainer, utils, HostInfo
1010
1011
1012 class UpdateTask(ContainerBaseTask):
1013- def __init__(self, container_id, config, lock, monitor, client, callback):
1014+ def __init__(self, container_id, config, lock, monitor, client):
1015 super().__init__(lock=lock, container_id=container_id, config=config,
1016- monitor=monitor, client=client, callback=callback)
1017+ monitor=monitor, client=client)
1018+
1019+ def _get_updated_locale(self):
1020+ host_locale = HostInfo.HostInfo().get_host_locale()
1021+
1022+ if host_locale == self._config.get_container_locale(self._container):
1023+ return None
1024+
1025+ return host_locale
1026
1027 def _run(self):
1028 utils.get_logger().debug("Updating container '%s'" % self._container)
1029 container = LibertineContainer(self._container, self._config, self._client)
1030 self._config.update_container_install_status(self._container, "updating")
1031- if not container.update_libertine_container():
1032+
1033+ new_locale = self._get_updated_locale()
1034+ if not container.update_libertine_container(new_locale):
1035 self._error("Failed to update container '%s'" % self._container)
1036
1037+ if new_locale:
1038+ self._config.update_container_locale(self._container, new_locale)
1039+
1040 self._config.update_container_install_status(self._container, "ready")
1041
1042 def _before(self):
1043
1044=== modified file 'tests/integration/CMakeLists.txt'
1045--- tests/integration/CMakeLists.txt 2017-03-27 20:06:39 +0000
1046+++ tests/integration/CMakeLists.txt 2017-04-07 16:34:30 +0000
1047@@ -1,7 +1,7 @@
1048 add_test(test_libertine_service dbus-run-session -- /usr/bin/python3 ${CMAKE_CURRENT_SOURCE_DIR}/test_libertine_service.py)
1049 set_tests_properties(test_libertine_service
1050 PROPERTIES ENVIRONMENT
1051- "LIBERTINE_DEBUG=2;PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;;PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};XDG_DATA_HOME=/tmp")
1052+ "LIBERTINED_TESTING=1;LIBERTINE_DEBUG=2;PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};")
1053
1054 add_executable(
1055 test_liblibertine
1056@@ -21,4 +21,4 @@
1057
1058 set_tests_properties(test_liblibertine
1059 PROPERTIES ENVIRONMENT
1060- "PYTHONPATH=${CMAKE_SOURCE_DIR}/python;PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};XDG_DATA_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data;XDG_CACHE_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data")
1061+ "LIBERTINE_DEBUG=2;LIBERTINED_TESTING=1;PYTHONPATH=${CMAKE_SOURCE_DIR}/python;PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};XDG_DATA_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data;XDG_CACHE_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data")
1062
1063=== modified file 'tests/integration/test_libertine_service.py'
1064--- tests/integration/test_libertine_service.py 2017-04-04 17:36:41 +0000
1065+++ tests/integration/test_libertine_service.py 2017-04-07 16:34:30 +0000
1066@@ -76,6 +76,7 @@
1067 self.path = None
1068
1069 self._libertined = self._bus.get_object(constants.SERVICE_NAME, constants.OPERATIONS_OBJECT)
1070+ self.path = None
1071
1072 self.signals.append(self._bus.add_signal_receiver(path=constants.OPERATIONS_MONITOR_OBJECT, handler_function=self._finished_handler,
1073 dbus_interface=constants.OPERATIONS_MONITOR_INTERFACE, signal_name='finished'))
1074
1075=== modified file 'tests/unit/service/CMakeLists.txt'
1076--- tests/unit/service/CMakeLists.txt 2017-03-07 20:48:11 +0000
1077+++ tests/unit/service/CMakeLists.txt 2017-04-07 16:34:30 +0000
1078@@ -2,7 +2,7 @@
1079 add_test(${test_name} /usr/bin/python3 ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.py)
1080 set_tests_properties(${test_name}
1081 PROPERTIES ENVIRONMENT
1082- "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;LIBERTINE_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
1083+ "LIBERTINED_TESTING=1;GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;LIBERTINE_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
1084 endfunction(create_service_unit_test)
1085
1086 create_service_unit_test(test_container)
1087
1088=== modified file 'tests/unit/service/tasks/test_app_info_task.py'
1089--- tests/unit/service/tasks/test_app_info_task.py 2017-03-07 19:41:49 +0000
1090+++ tests/unit/service/tasks/test_app_info_task.py 2017-04-07 16:34:30 +0000
1091@@ -33,7 +33,6 @@
1092
1093 self.cache.app_info.return_value = {}
1094 task = tasks.AppInfoTask('palpatine', self.cache, 'lightside', [1, 2], self.config, self.monitor, callback)
1095- task._instant_callback = True
1096 task.start().join()
1097
1098 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Could not find app info for \'lightside\' in container \'palpatine\'')
1099@@ -50,7 +49,6 @@
1100 self.cache.app_info.return_value = {'package': 'darkside-common'}
1101 self.config.get_package_install_status.return_value = 'installed'
1102 task = tasks.AppInfoTask('palpatine', self.cache, 'darkside', [1, 2, 3], self.config, self.monitor, callback)
1103- task._instant_callback = True
1104 task.start().join()
1105
1106 self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, str({'package': 'darkside-common', 'status': 'installed', 'task_ids': [1, 2, 3]}))
1107
1108=== modified file 'tests/unit/service/tasks/test_container_info_task.py'
1109--- tests/unit/service/tasks/test_container_info_task.py 2017-03-07 19:41:49 +0000
1110+++ tests/unit/service/tasks/test_container_info_task.py 2017-04-07 16:34:30 +0000
1111@@ -37,7 +37,6 @@
1112 self.config.get_container_install_status.return_value = 'ready'
1113 self.config.get_container_name.return_value = 'Palpatine'
1114 task = tasks.ContainerInfoTask('palpatine', [1, 2, 3], self.config, self.monitor, callback)
1115- task._instant_callback = True
1116 task.start().join()
1117
1118 self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, unittest.mock.ANY)
1119
1120=== modified file 'tests/unit/service/tasks/test_create_task.py'
1121--- tests/unit/service/tasks/test_create_task.py 2017-03-09 16:02:22 +0000
1122+++ tests/unit/service/tasks/test_create_task.py 2017-04-07 16:34:30 +0000
1123@@ -37,7 +37,6 @@
1124 self.monitor.done.return_value = False
1125 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
1126 self.config, self.lock, self.monitor, self.client, self.callback)
1127- task._instant_callback = True
1128
1129 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1130 MockHostInfo.return_value.is_distro_valid.return_value = True
1131@@ -60,7 +59,6 @@
1132 self.monitor.done.return_value = False
1133 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False,
1134 self.config, self.lock, self.monitor, self.client, self.callback)
1135- task._instant_callback = True
1136
1137 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1138 MockHostInfo.return_value.is_distro_valid.return_value = True
1139@@ -81,7 +79,6 @@
1140 self.config.container_exists.return_value = False
1141 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
1142 self.config, self.lock, self.monitor, self.client, self.callback)
1143- task._instant_callback = True
1144
1145 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1146 MockHostInfo.return_value.is_distro_valid.return_value = True
1147@@ -103,7 +100,6 @@
1148 self.config.container_exists.return_value = True
1149 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
1150 self.config, self.lock, self.monitor, self.client, self.callback)
1151- task._instant_callback = True
1152 task.start().join()
1153
1154 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Container \'palpatine\' already exists')
1155@@ -115,7 +111,6 @@
1156 MockHostInfo.return_value.is_distro_valid.return_value = False
1157 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False,
1158 self.config, self.lock, self.monitor, self.client, self.callback)
1159- task._instant_callback = True
1160 task.start().join()
1161
1162 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Invalid distro \'vesty\'.')
1163@@ -128,7 +123,6 @@
1164 MockHostInfo.return_value.has_lxc_support.return_value = False
1165 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False,
1166 self.config, self.lock, self.monitor, self.client, self.callback)
1167- task._instant_callback = True
1168 task.start().join()
1169
1170 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, \
1171@@ -140,7 +134,6 @@
1172 self.monitor.done.return_value = False
1173 task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config,
1174 self.lock, self.monitor, self.client, self.callback)
1175- task._instant_callback = True
1176
1177 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1178 MockHostInfo.return_value.is_distro_valid.return_value = True
1179@@ -163,7 +156,6 @@
1180 self.monitor.done.return_value = False
1181 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True,
1182 self.config, self.lock, self.monitor, self.client, self.callback)
1183- task._instant_callback = True
1184
1185 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1186 MockHostInfo.return_value.is_distro_valid.return_value = True
1187@@ -186,7 +178,6 @@
1188 self.monitor.done.return_value = False
1189 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False,
1190 self.config, self.lock, self.monitor, self.client, self.callback)
1191- task._instant_callback = True
1192
1193 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1194 MockHostInfo.return_value.is_distro_valid.return_value = True
1195@@ -209,7 +200,6 @@
1196 self.monitor.done.return_value = False
1197 task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False,
1198 self.config, self.lock, self.monitor, self.client, self.callback)
1199- task._instant_callback = True
1200
1201 with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1202 MockHostInfo.return_value.has_lxc_support.return_value = True
1203
1204=== modified file 'tests/unit/service/tasks/test_destroy_task.py'
1205--- tests/unit/service/tasks/test_destroy_task.py 2017-03-09 16:02:22 +0000
1206+++ tests/unit/service/tasks/test_destroy_task.py 2017-04-07 16:34:30 +0000
1207@@ -36,7 +36,6 @@
1208 self.config._get_value_by_key.return_value = ''
1209 self.monitor.done.return_value = False
1210 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1211- task._instant_callback = True
1212
1213 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
1214 MockContainer.return_value.destroy_libertine_container.return_value = True
1215@@ -48,7 +47,6 @@
1216 def test_sends_error_on_failed_destroy(self):
1217 self.config._get_value_by_key.return_value = 'ready'
1218 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1219- task._instant_callback = True
1220
1221 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
1222 MockContainer.return_value.destroy_libertine_container.return_value = False
1223@@ -66,7 +64,6 @@
1224 self.config._get_value_by_key.return_value = 'ready'
1225 self.monitor.done.return_value = False
1226 task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1227- task._instant_callback = True
1228
1229 with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
1230 MockContainer.return_value.destroy_libertine_container.return_value = True
1231
1232=== modified file 'tests/unit/service/tasks/test_install_task.py'
1233--- tests/unit/service/tasks/test_install_task.py 2017-03-09 16:02:22 +0000
1234+++ tests/unit/service/tasks/test_install_task.py 2017-04-07 16:34:30 +0000
1235@@ -35,7 +35,6 @@
1236 def test_sends_error_on_existing_package(self):
1237 self.config.package_exists.return_value = True
1238 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1239- task._instant_callback = True
1240 task.start().join()
1241
1242 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Package \'darkside-common\' already exists, skipping install')
1243@@ -44,7 +43,6 @@
1244 def test_sends_error_on_failed_install(self):
1245 self.config.package_exists.return_value = False
1246 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1247- task._instant_callback = True
1248
1249 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
1250 MockContainer.return_value.install_package.return_value = False
1251@@ -59,7 +57,6 @@
1252 self.config.package_exists.return_value = False
1253 self.monitor.done.return_value = False
1254 task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1255- task._instant_callback = True
1256
1257 with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
1258 MockContainer.return_value.install_package.return_value = True
1259
1260=== modified file 'tests/unit/service/tasks/test_list_app_ids_task.py'
1261--- tests/unit/service/tasks/test_list_app_ids_task.py 2017-03-07 19:41:49 +0000
1262+++ tests/unit/service/tasks/test_list_app_ids_task.py 2017-04-07 16:34:30 +0000
1263@@ -34,7 +34,6 @@
1264 def test_sends_error_on_non_existent_container(self):
1265 self.config.container_exists.return_value = False
1266 task = tasks.ListAppIdsTask('palpatine', self.config, self.monitor, self.callback)
1267- task._instant_callback = True
1268
1269 with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
1270 task.start().join()
1271@@ -46,7 +45,6 @@
1272 self.config.container_exists.return_value = True
1273 self.monitor.done.return_value = False
1274 task = tasks.ListAppIdsTask('palpatine', self.config, self.monitor, self.callback)
1275- task._instant_callback = True
1276
1277 with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
1278 MockContainer.return_value.list_app_ids.return_value = '["palpatine_gedit_0.0","palpatine_xterm_0.0"]'
1279
1280=== modified file 'tests/unit/service/tasks/test_list_task.py'
1281--- tests/unit/service/tasks/test_list_task.py 2017-03-07 19:41:49 +0000
1282+++ tests/unit/service/tasks/test_list_task.py 2017-04-07 16:34:30 +0000
1283@@ -35,7 +35,6 @@
1284 self.monitor.done.return_value = False
1285
1286 task = tasks.ListTask(self.config, self.monitor, callback)
1287- task._instant_callback = True
1288
1289 self.config.get_containers.return_value = ['palatine', 'vader', 'maul']
1290 task.start().join()
1291
1292=== modified file 'tests/unit/service/tasks/test_remove_task.py'
1293--- tests/unit/service/tasks/test_remove_task.py 2017-03-09 16:02:22 +0000
1294+++ tests/unit/service/tasks/test_remove_task.py 2017-04-07 16:34:30 +0000
1295@@ -35,7 +35,6 @@
1296 def test_sends_error_on_non_installed_package(self):
1297 self.config.get_package_install_status.return_value = 'installing'
1298 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1299- task._instant_callback = True
1300 task.start().join()
1301
1302 self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Package \'darkside-common\' not installed, skipping remove')
1303@@ -44,7 +43,6 @@
1304 def test_sends_error_on_failed_install(self):
1305 self.config.get_package_install_status.return_value = 'installed'
1306 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1307- task._instant_callback = True
1308
1309 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
1310 MockContainer.return_value.remove_package.return_value = False
1311@@ -61,7 +59,6 @@
1312 self.config.get_package_install_status.return_value = 'installed'
1313 self.monitor.done.return_value = False
1314 task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1315- task._instant_callback = True
1316
1317 with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
1318 MockContainer.return_value.remove_package.return_value = True
1319
1320=== modified file 'tests/unit/service/tasks/test_search_task.py'
1321--- tests/unit/service/tasks/test_search_task.py 2017-03-07 19:41:49 +0000
1322+++ tests/unit/service/tasks/test_search_task.py 2017-04-07 16:34:30 +0000
1323@@ -33,7 +33,6 @@
1324 def test_successfully_lists_apps(self):
1325 self.monitor.done.return_value = False
1326 task = tasks.SearchTask('palpatine', self.cache, 'jarjar', self.monitor, self.callback)
1327- task._instant_callback = True
1328
1329 self.cache.search.return_value = ['jarjar', 'sidius']
1330 task.start().join()
1331
1332=== modified file 'tests/unit/service/tasks/test_update_task.py'
1333--- tests/unit/service/tasks/test_update_task.py 2017-03-09 16:02:22 +0000
1334+++ tests/unit/service/tasks/test_update_task.py 2017-04-07 16:34:30 +0000
1335@@ -35,7 +35,6 @@
1336 def test_sends_error_on_non_existent_container(self):
1337 self.config.container_exists.return_value = False
1338 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1339- task._instant_callback = True
1340
1341 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1342 task.start().join()
1343@@ -47,7 +46,6 @@
1344 def test_sends_error_on_failed_update(self):
1345 self.config.container_exists.return_value = True
1346 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1347- task._instant_callback = True
1348
1349 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1350 MockContainer.return_value.update_libertine_container.return_value = False
1351@@ -65,7 +63,6 @@
1352 self.config.container_exists.return_value = True
1353 self.monitor.done.return_value = False
1354 task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.client, self.callback)
1355- task._instant_callback = True
1356
1357 with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
1358 MockContainer.return_value.update_libertine_container.return_value = True
1359
1360=== modified file 'tests/unit/service/test_container.py'
1361--- tests/unit/service/test_container.py 2017-03-16 19:59:08 +0000
1362+++ tests/unit/service/test_container.py 2017-04-07 16:34:30 +0000
1363@@ -30,7 +30,7 @@
1364 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1365 with unittest.mock.patch('libertine.service.container.SearchTask') as MockSearchTask:
1366 c.search('darkseid')
1367- MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._monitor, unittest.mock.ANY)
1368+ MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._config, self._monitor, unittest.mock.ANY)
1369 MockSearchTask.return_value.start.assert_called_once_with()
1370
1371 def test_app_info_creates_app_info_task(self):
1372@@ -49,7 +49,7 @@
1373 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1374 MockInstallTask.return_value.package = 'darkside'
1375 MockInstallTask.return_value.matches.return_value = False
1376- install_task_id = c.install('darkside')
1377+ install_task_id = c.install('darkside', False)
1378 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
1379 MockRemoveTask.return_value.package = 'darkside'
1380 remove_task_id = c.remove('darkside')
1381@@ -62,18 +62,18 @@
1382 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1383 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1384 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1385- c.install('force')
1386- MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1387+ c.install('force', False)
1388+ MockInstallTask.assert_called_once_with('force', 'palpatine', False, self._config, unittest.mock.ANY, self._monitor, self._client)
1389 MockInstallTask.return_value.start.assert_called_once_with()
1390
1391 def test_install_only_calls_once_when_unfinished(self):
1392 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1393 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1394 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1395- c.install('darkside')
1396- c.install('darkside')
1397- c.install('darkside')
1398- MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1399+ c.install('darkside', False)
1400+ c.install('darkside', False)
1401+ c.install('darkside', False)
1402+ MockInstallTask.assert_called_once_with('darkside', 'palpatine', False, self._config, unittest.mock.ANY, self._monitor, self._client)
1403 MockInstallTask.return_value.start.assert_called_once_with()
1404
1405 def test_remove_creates_remove_task(self):
1406@@ -81,7 +81,7 @@
1407 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1408 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
1409 c.remove('force')
1410- MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1411+ MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client)
1412 MockRemoveTask.return_value.start.assert_called_once_with()
1413
1414 def test_remove_only_calls_once_when_unfinished(self):
1415@@ -91,7 +91,7 @@
1416 c.remove('darkside')
1417 c.remove('darkside')
1418 c.remove('darkside')
1419- MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1420+ MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, self._client)
1421 MockRemoveTask.return_value.start.assert_called_once_with()
1422
1423 def test_create_creates_create_task(self):
1424@@ -100,7 +100,7 @@
1425 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
1426 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1427 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
1428- self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1429+ self._config, unittest.mock.ANY, self._monitor, self._client)
1430 MockCreateTask.return_value.start.assert_called_once_with()
1431
1432 def test_create_only_calls_once_when_unfinished(self):
1433@@ -111,25 +111,25 @@
1434 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1435 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
1436 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
1437- self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1438+ self._config, unittest.mock.ANY, self._monitor, self._client)
1439 MockCreateTask.return_value.start.assert_called_once_with()
1440
1441 def test_destroy_creates_destroy_task(self):
1442 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1443 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1444 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
1445- c.destroy()
1446- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1447+ c.destroy(False)
1448+ MockDestroyTask.assert_called_once_with('palpatine', self._config, False, unittest.mock.ANY, self._monitor, self._client)
1449 MockDestroyTask.return_value.start.assert_called_once_with()
1450
1451 def test_destroy_only_calls_once_when_unfinished(self):
1452 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1453 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1454 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
1455- c.destroy()
1456- c.destroy()
1457- c.destroy()
1458- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1459+ c.destroy(False)
1460+ c.destroy(False)
1461+ c.destroy(False)
1462+ MockDestroyTask.assert_called_once_with('palpatine', self._config, False, unittest.mock.ANY, self._monitor, self._client)
1463 MockDestroyTask.return_value.start.assert_called_once_with()
1464
1465 def test_update_creates_update_task(self):
1466@@ -137,7 +137,7 @@
1467 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1468 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
1469 c.update()
1470- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1471+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client)
1472 MockUpdateTask.return_value.start.assert_called_once_with()
1473
1474 def test_update_only_calls_once_when_unfinished(self):
1475@@ -147,7 +147,7 @@
1476 c.update()
1477 c.update()
1478 c.update()
1479- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client, unittest.mock.ANY)
1480+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, self._client)
1481 MockUpdateTask.return_value.start.assert_called_once_with()
1482
1483 def test_list_app_ids_creates_list_app_ids_task(self):
1484@@ -155,21 +155,21 @@
1485 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1486 with unittest.mock.patch('libertine.service.container.ListAppIdsTask') as MockListAppIdsTask:
1487 c.list_app_ids()
1488- MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._monitor, self._client, unittest.mock.ANY)
1489+ MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._monitor, self._client)
1490 MockListAppIdsTask.return_value.start.assert_called_once_with()
1491
1492- def test_removes_task_during_callback(self):
1493+ def test_removes_task_during_cleanup(self):
1494 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
1495 c = container.Container('palpatine', self._config, self._monitor, self._client, lambda task: task)
1496 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1497 MockInstallTask.return_value.package = 'force'
1498- c.install('force')
1499+ c.install('force', False)
1500 self.assertEqual(1, len(MockInstallTask.return_value.start.mock_calls)) # ensure initial mocks were called
1501- c.install('force')
1502+ c.install('force', False)
1503 self.assertEqual(1, len(MockInstallTask.return_value.start.mock_calls)) # ensure no more mocks were called
1504- name, args, kwargs = MockInstallTask.mock_calls[0]
1505- args[len(args)-1](MockInstallTask.return_value.start.return_value)
1506- c.install('force')
1507+ MockInstallTask.return_value.should_delete = True
1508+ c._cleanup()
1509+ c.install('force', False)
1510 self.assertEqual(2, len(MockInstallTask.return_value.start.mock_calls)) # ensure mocks were called again
1511
1512 def test_completing_all_tasks_fires_callback(self):
1513@@ -179,9 +179,9 @@
1514 self._container_id = container.id
1515 c = container.Container('palpatine', self._config, self._monitor, self._client, callback)
1516 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
1517- c.install('force')
1518- name, args, kwargs = MockInstallTask.mock_calls[0]
1519- args[len(args)-1](MockInstallTask.return_value)
1520+ c.install('force', False)
1521+ MockInstallTask.return_value.should_delete = True
1522+ c._cleanup()
1523 self.assertEqual('palpatine', self._container_id)
1524
1525
1526
1527=== modified file 'tests/unit/service/test_task_dispatcher.py'
1528--- tests/unit/service/test_task_dispatcher.py 2017-03-09 16:02:22 +0000
1529+++ tests/unit/service/test_task_dispatcher.py 2017-04-07 16:34:30 +0000
1530@@ -46,8 +46,8 @@
1531 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
1532 c = MockContainer.return_value
1533 c.install.return_value = 123
1534- self.assertEqual(123, self._dispatcher.install('palpatine', 'darkside'))
1535- c.install.assert_called_once_with('darkside')
1536+ self.assertEqual(123, self._dispatcher.install('palpatine', 'darkside', False))
1537+ c.install.assert_called_once_with('darkside', False)
1538
1539 def test_remove_calls_remove_on_container(self):
1540 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
1541@@ -67,8 +67,8 @@
1542 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
1543 c = MockContainer.return_value
1544 c.destroy.return_value = 123
1545- self.assertEqual(123, self._dispatcher.destroy('palpatine'))
1546- c.destroy.assert_called_once_with()
1547+ self.assertEqual(123, self._dispatcher.destroy('palpatine', False))
1548+ c.destroy.assert_called_once_with(False)
1549
1550 def test_update_calls_update_on_container(self):
1551 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
1552@@ -112,7 +112,7 @@
1553 task = MockContainerInfoTask.return_value
1554 task.id = 123
1555 self.assertEqual(123, self._dispatcher.container_info('palpatine'))
1556- MockContainerInfoTask.assert_called_once_with('palpatine', [], unittest.mock.ANY, self._connection, unittest.mock.ANY)
1557+ MockContainerInfoTask.assert_called_once_with('palpatine', [], unittest.mock.ANY, self._connection)
1558 task.start.assert_called_once_with()
1559
1560 def test_container_info_forwards_container_task_ids(self):
1561@@ -124,7 +124,7 @@
1562 c.id = 'palpatine'
1563 self._dispatcher.list_app_ids('palpatine') # creates container
1564 self._dispatcher.container_info('palpatine')
1565- MockContainerInfoTask.assert_called_once_with('palpatine', [1, 2, 3], unittest.mock.ANY, self._connection, unittest.mock.ANY)
1566+ MockContainerInfoTask.assert_called_once_with('palpatine', [1, 2, 3], unittest.mock.ANY, self._connection)
1567 task.start.assert_called_once_with()
1568
1569 def test_list_creates_list_task(self):
1570@@ -132,16 +132,17 @@
1571 task = MockListTask.return_value
1572 task.id = 123
1573 self.assertEqual(123, self._dispatcher.list())
1574- MockListTask.assert_called_once_with(unittest.mock.ANY, self._connection, unittest.mock.ANY)
1575+ MockListTask.assert_called_once_with(unittest.mock.ANY, self._connection)
1576 task.start.assert_called_once_with()
1577
1578 def test_containerless_tasks_are_cleaned_up(self):
1579 with unittest.mock.patch('libertine.service.task_dispatcher.ListTask') as MockListTask:
1580 self._dispatcher.list()
1581- MockListTask.assert_called_once_with(unittest.mock.ANY, self._connection, unittest.mock.ANY)
1582+ MockListTask.assert_called_once_with(unittest.mock.ANY, self._connection)
1583 name, args, kwargs = MockListTask.mock_calls[0]
1584 self.assertEqual(1, len(self._dispatcher._tasks))
1585- args[len(args)-1](MockListTask.return_value)
1586+ MockListTask.return_value.should_delete = True
1587+ self._dispatcher._cleanup()
1588 self.assertEqual(0, len(self._dispatcher._tasks))
1589
1590
1591
1592=== modified file 'tools/libertined'
1593--- tools/libertined 2017-04-06 14:37:00 +0000
1594+++ tools/libertined 2017-04-07 16:34:30 +0000
1595@@ -20,7 +20,6 @@
1596 import dbus
1597 import os
1598 import signal
1599-import sys
1600
1601 from dbus.mainloop.glib import DBusGMainLoop
1602 from gi.repository import GLib

Subscribers

People subscribed via source and target branches