Merge lp:~townsend/libertine/1.5.1-release into lp:libertine/trunk

Proposed by Christopher Townsend
Status: Merged
Approved by: Larry Price
Approved revision: 184
Merged at revision: 182
Proposed branch: lp:~townsend/libertine/1.5.1-release
Merge into: lp:libertine/trunk
Diff against target: 927 lines (+276/-122)
17 files modified
CMakeLists.txt (+1/-1)
data/libertine-lxc.conf (+0/-1)
debian/changelog (+27/-0)
liblibertine/libertine.cpp (+2/-18)
python/libertine/ChrootContainer.py (+8/-13)
python/libertine/ContainersConfig.py (+6/-0)
python/libertine/HostInfo.py (+12/-0)
python/libertine/Libertine.py (+82/-13)
python/libertine/LxcContainer.py (+7/-8)
python/libertine/LxdContainer.py (+95/-41)
python/libertine/lifecycle/ContainerLifecycleService.py (+7/-7)
python/libertine/utils.py (+3/-11)
snapcraft.yaml (+1/-1)
tools/libertine-container-manager (+21/-4)
tools/libertine-container-manager.1 (+1/-1)
tools/libertine-lxc-manager (+1/-1)
tools/libertine-lxd-manager (+2/-2)
To merge this branch: bzr merge lp:~townsend/libertine/1.5.1-release
Reviewer Review Type Date Requested Status
Larry Price Approve
Review via email: mp+314744@code.launchpad.net

Commit message

* Remove the /tmp/.X11-unix umount during LXC container start for operations as it seems it's not needed. (LP: #1654650)
* Remove extra finish_application() in chroot backend.
* Set container's locale and language based on the host including installing necessary language packs. (LP: #1609982)
* Bump version to 1.5.1.
* Manually execute lxd bind mount script to fix /run/user and remove service. (LP: #1654647)
* Convert results to dicts on operation/application collision in container lifecycle managers.
* Stop bind-mounting /usr/lib/locale and let environment do all the work. (LP: #1654648)
* Mount lxd home directory in $HOME/.local/libertine-container where it belongs.
* Manually wait for lxd container to stop when specified after calling the service. (LP: #1655980)
* Ask for container user password when creating lxd containers. (LP: #1655977)
* Bind-mount lxd container applications and icons directories into user's home directory.

To post a comment you must log in.
Revision history for this message
Larry Price (larryprice) wrote :

lgtm!

review: Approve
lp:~townsend/libertine/1.5.1-release updated
183. By Christopher Townsend

Merge lp:libertine for fix on starting the window manager.

184. By Christopher Townsend

Merge lp:libertine for fix to remove bind-mount rootfs directories in LXD.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-01-05 18:29:51 +0000
3+++ CMakeLists.txt 2017-01-18 14:37:20 +0000
4@@ -2,7 +2,7 @@
5 cmake_policy(SET CMP0048 NEW)
6
7 project(libertine
8- VERSION 1.5)
9+ VERSION 1.5.1)
10
11 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}")
12
13
14=== modified file 'data/libertine-lxc.conf'
15--- data/libertine-lxc.conf 2016-03-21 19:26:22 +0000
16+++ data/libertine-lxc.conf 2017-01-18 14:37:20 +0000
17@@ -3,5 +3,4 @@
18 lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir
19 lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file
20 lxc.mount.entry = /dev/fuse dev/fuse none bind,optional,create=file
21-lxc.mount.entry = /usr/lib/locale usr/lib/locale none optional,bind
22 lxc.tty = 0
23
24=== modified file 'debian/changelog'
25--- debian/changelog 2017-01-05 20:20:33 +0000
26+++ debian/changelog 2017-01-18 14:37:20 +0000
27@@ -1,3 +1,30 @@
28+libertine (1.5.1-0ubuntu1) UNRELEASED; urgency=medium
29+
30+ [ Chris Townsend ]
31+ * Remove the /tmp/.X11-unix umount during LXC container start for operations
32+ as it seems it's not needed. (LP: #1654650)
33+ * Remove extra finish_application() in chroot backend.
34+ * Set container's locale and language based on the host including installing
35+ necessary language packs. (LP: #1609982)
36+ * Bump version to 1.5.1.
37+
38+ [ Larry Price ]
39+ * Manually execute lxd bind mount script to fix /run/user and remove
40+ service. (LP: #1654647)
41+ * Convert results to dicts on operation/application collision in container
42+ lifecycle managers.
43+ * Stop bind-mounting /usr/lib/locale and let environment do all the work.
44+ (LP: #1654648)
45+ * Mount lxd home directory in $HOME/.local/libertine-container where it
46+ belongs.
47+ * Manually wait for lxd container to stop when specified after calling the
48+ service. (LP: #1655980)
49+ * Ask for container user password when creating lxd containers. (LP: #1655977)
50+ * Bind-mount lxd container applications and icons directories into user's
51+ home directory.
52+
53+ -- Chris Townsend <christopher.townsend@canonical.com> Fri, 13 Jan 2017 14:59:52 -0500
54+
55 libertine (1.5+17.04.20170105.1-0ubuntu1) zesty; urgency=medium
56
57 [ Chris Townsend ]
58
59=== modified file 'liblibertine/libertine.cpp'
60--- liblibertine/libertine.cpp 2016-12-07 18:04:08 +0000
61+++ liblibertine/libertine.cpp 2017-01-18 14:37:20 +0000
62@@ -148,16 +148,8 @@
63 g_return_val_if_fail(container_id != nullptr, nullptr);
64 LibertineConfig config;
65 ContainerConfigList container_list(&config);
66- gchar * path = nullptr;
67
68- if (g_strcmp0((gchar*)container_list.getContainerType(container_id).toStdString().c_str(), "lxd") == 0)
69- {
70- path = g_build_filename("/", "var", "lib", "lxd", "containers", container_id, "rootfs", nullptr);
71- }
72- else
73- {
74- path = g_build_filename(g_get_user_cache_dir(), "libertine-container", container_id, "rootfs", nullptr);
75- }
76+ gchar * path = g_build_filename(g_get_user_cache_dir(), "libertine-container", container_id, "rootfs", nullptr);
77
78 if (g_file_test(path, G_FILE_TEST_EXISTS))
79 {
80@@ -175,16 +167,8 @@
81 g_return_val_if_fail(container_id != nullptr, nullptr);
82 LibertineConfig config;
83 ContainerConfigList container_list(&config);
84- gchar * path = nullptr;
85
86- if (g_strcmp0((gchar*)container_list.getContainerType(container_id).toStdString().c_str(), "lxd") == 0)
87- {
88- path = g_build_filename("/", "var", "lib", "lxd", "containers", container_id, "rootfs", "home", g_get_user_name(), nullptr);
89- }
90- else
91- {
92- path = g_build_filename(g_get_user_data_dir(), "libertine-container", "user-data", container_id, nullptr);
93- }
94+ gchar * path = g_build_filename(g_get_user_data_dir(), "libertine-container", "user-data", container_id, nullptr);
95
96 if (g_file_test(path, G_FILE_TEST_EXISTS))
97 {
98
99=== modified file 'python/libertine/ChrootContainer.py'
100--- python/libertine/ChrootContainer.py 2017-01-04 20:22:33 +0000
101+++ python/libertine/ChrootContainer.py 2017-01-18 14:37:20 +0000
102@@ -66,13 +66,7 @@
103 return cmd.wait()
104
105 def destroy_libertine_container(self):
106- container_root = os.path.join(utils.get_libertine_containers_dir_path(), self.container_id)
107- try:
108- shutil.rmtree(container_root)
109- return True
110- except Exception as e:
111- utils.get_logger().error("%s" % e)
112- return False
113+ return self._delete_rootfs()
114
115 def create_libertine_container(self, password=None, multiarch=False):
116 # Create the actual chroot
117@@ -120,6 +114,8 @@
118
119 utils.create_libertine_user_data_dir(self.container_id)
120
121+ self.update_locale()
122+
123 if multiarch and self.architecture == 'amd64':
124 utils.get_logger().info("Adding i386 multiarch support...")
125 self.run_in_container("dpkg --add-architecture i386")
126@@ -146,10 +142,12 @@
127 # Check if the container was created as root and chown the user directories as necessary
128 chown_recursive_dirs(utils.get_libertine_container_userdata_dir_path(self.container_id))
129
130+ super().create_libertine_container()
131+
132 return True
133
134- def update_packages(self):
135- retcode = super().update_packages()
136+ def update_packages(self, new_locale=None):
137+ retcode = super().update_packages(new_locale)
138 self._run_ldconfig()
139 return retcode == 0
140
141@@ -229,7 +227,7 @@
142 proot_cmd = self._build_proot_command()
143
144 args = shlex.split(proot_cmd)
145- args.extend(utils.setup_window_manager(self.container_id, enable_toolbars=True))
146+ args.extend(self.setup_window_manager(enable_toolbars=True))
147 self._window_manager = psutil.Popen(args, env=environ)
148
149 args = shlex.split(proot_cmd)
150@@ -248,6 +246,3 @@
151 args = shlex.split(command_line)
152 app = subprocess.Popen(args)
153 return app
154-
155- def finish_application(self, app):
156- app.wait()
157
158=== modified file 'python/libertine/ContainersConfig.py'
159--- python/libertine/ContainersConfig.py 2016-12-07 21:50:36 +0000
160+++ python/libertine/ContainersConfig.py 2017-01-18 14:37:20 +0000
161@@ -296,6 +296,12 @@
162 else:
163 return multiarch_support
164
165+ def update_container_locale(self, container_id, locale):
166+ self._set_value_by_key(container_id, 'locale', locale)
167+
168+ def get_container_locale(self, container_id):
169+ return self._get_value_by_key(container_id, 'locale')
170+
171 """
172 Operations for archive (PPA) maintenance in a Libertine container.
173 """
174
175=== modified file 'python/libertine/HostInfo.py'
176--- python/libertine/HostInfo.py 2016-11-21 17:18:55 +0000
177+++ python/libertine/HostInfo.py 2017-01-18 14:37:20 +0000
178@@ -12,6 +12,7 @@
179 # You should have received a copy of the GNU General Public License along
180 # with this program. If not, see <http://www.gnu.org/licenses/>.
181
182+import locale
183 import lsb_release
184 import os
185 import platform
186@@ -74,3 +75,14 @@
187 def get_host_timezone(self):
188 with open(os.path.join('/', 'etc', 'timezone'), 'r') as fd:
189 return fd.read().strip('\n')
190+
191+ def get_host_locale(self):
192+ host_locale = locale.getlocale()
193+ full_locale = None
194+
195+ if len(host_locale) == 2:
196+ full_locale = "{}.{}".format(host_locale[0], host_locale[1])
197+ elif len(host_locale) == 1:
198+ full_locale = "{}".format(host_locale[0])
199+
200+ return full_locale
201
202=== modified file 'python/libertine/Libertine.py'
203--- python/libertine/Libertine.py 2017-01-03 17:51:30 +0000
204+++ python/libertine/Libertine.py 2017-01-18 14:37:20 +0000
205@@ -16,7 +16,6 @@
206 from gi.repository import Libertine
207 import abc
208 import contextlib
209-import libertine.utils
210 import os
211 import shutil
212
213@@ -82,10 +81,15 @@
214
215 :param container_id: The machine-readable container name.
216 """
217- def __init__(self, container_id):
218+ def __init__(self, container_id, containers_config=None):
219+ if containers_config is None:
220+ containers_config = ContainersConfig()
221+
222 self.container_type = 'unknown'
223 self.container_id = container_id
224- self.root_path = libertine.utils.get_libertine_container_rootfs_path(self.container_id)
225+ self.root_path = utils.get_libertine_container_rootfs_path(self.container_id)
226+ self.locale = containers_config.get_container_locale(container_id)
227+ self.language = self._get_language_from_locale()
228 self.default_packages = ['matchbox-window-manager',
229 'libnss-extrausers',
230 'humanity-icon-theme',
231@@ -93,8 +97,62 @@
232 'maliit-inputcontext-gtk3',
233 'maliit-framework']
234
235+ def _get_language_from_locale(self):
236+ language = None
237+
238+ if self.locale is not None:
239+ language = self.locale.split('.')[0]
240+ if not language.startswith('zh_'):
241+ language = language.split('_')[0]
242+ elif language.startswith('zh_CN'):
243+ language = 'zh-hans'
244+ else:
245+ language = 'zh-hant'
246+
247+ return language
248+
249+ def _binary_exists(self, binary):
250+ return self.run_in_container("bash -c \"which {} &> /dev/null\"".format(binary)) == 0
251+
252+ def _delete_rootfs(self):
253+ container_root = os.path.join(utils.get_libertine_containers_dir_path(), self.container_id)
254+ if not os.path.exists(container_root):
255+ return True
256+
257+ try:
258+ shutil.rmtree(container_root)
259+ return True
260+ except Exception as e:
261+ utils.get_logger().error("%s" % e)
262+ return False
263+
264+ def setup_window_manager(self, enable_toolbars=False):
265+ if self._binary_exists('matchbox-window-manager'):
266+ if enable_toolbars:
267+ return ['matchbox-window-manager']
268+
269+ return ['matchbox-window-manager', '-use_titlebar', 'no']
270+ else:
271+ return ['compiz']
272+
273+
274+ def check_language_support(self):
275+ if not self._binary_exists('check-language-support'):
276+ self.install_package('language-selector-common', update_cache=False)
277+
278+ self.run_in_container("bash -c \"{} install $(check-language-support -l {})\"".format(_apt_command_prefix(), self.language))
279+
280+ def update_locale(self):
281+ self.run_in_container("locale-gen {}".format(self.locale))
282+
283+ def install_base_language_packs(self):
284+ base_language_packs = ['language-pack-{}', 'language-pack-gnome-{}']
285+
286+ for language_pack in [p.format(self.language) for p in base_language_packs]:
287+ self.install_package(language_pack, update_cache=False)
288+
289 def create_libertine_container(self, password=None, multiarch=False):
290- pass
291+ self.install_base_language_packs()
292
293 def destroy_libertine_container(self):
294 pass
295@@ -150,11 +208,18 @@
296 """
297 return self.run_in_container(_apt_command_prefix() + 'update')
298
299- def update_packages(self):
300+ def update_packages(self, new_locale=None):
301 """
302 Updates all packages installed in the container.
303 """
304 self.update_apt_cache()
305+
306+ if new_locale:
307+ self.locale = new_locale
308+ self.language = self._get_language_from_locale()
309+ self.update_locale()
310+ self.install_base_language_packs()
311+
312 return self.run_in_container(_apt_command_prefix() + '--force-yes dist-upgrade') == 0
313
314 def install_package(self, package_name, no_dialog=False, update_cache=True):
315@@ -185,7 +250,11 @@
316 else:
317 if no_dialog:
318 os.environ['DEBIAN_FRONTEND'] = 'teletype'
319- return self.run_in_container(_apt_command_prefix() + " install '" + package_name + "'") == 0
320+ ret = self.run_in_container(_apt_command_prefix() + " install '" + package_name + "'") == 0
321+
322+ self.check_language_support()
323+
324+ return ret
325
326 def remove_package(self, package_name):
327 """
328@@ -219,7 +288,7 @@
329 :param archive: The configuration command to run.
330 :param public_key_file: file containing the public key used to sign this archive
331 """
332- if not os.path.exists(os.path.join(self.root_path, 'usr', 'bin', 'add-apt-repository')):
333+ if not self._binary_exists('add-apt-repository'):
334 self.install_package("software-properties-common")
335 if 'https://' in archive and not os.path.exists(os.path.join(self.root_path, 'usr', 'lib', 'apt', 'methods', 'https')):
336 self.install_package("apt-transport-https")
337@@ -254,8 +323,8 @@
338 """
339 A concrete mock container type. Used for unit testing.
340 """
341- def __init__(self, container_id):
342- super().__init__(container_id)
343+ def __init__(self, container_id, containers_config=None):
344+ super().__init__(container_id, containers_config)
345 self.container_type = "mock"
346
347 def create_libertine_container(self, password=None, multiarch=False):
348@@ -264,7 +333,7 @@
349 def destroy_libertine_container(self):
350 return True
351
352- def update_packages(self):
353+ def update_packages(self, new_locale=None):
354 return True
355
356 def install_package(self, package_name, no_dialog=False, update_cache=True):
357@@ -328,7 +397,7 @@
358 from libertine.ChrootContainer import LibertineChroot
359 self.container = LibertineChroot(container_id)
360 elif container_type == "mock":
361- self.container = LibertineMock(container_id)
362+ self.container = LibertineMock(container_id, self.containers_config)
363 else:
364 raise RuntimeError("Unsupported container type %s" % container_type)
365
366@@ -363,13 +432,13 @@
367
368 return self.container.create_libertine_container(password, multiarch)
369
370- def update_libertine_container(self):
371+ def update_libertine_container(self, new_locale=None):
372 """
373 Updates the contents of the container.
374 """
375 try:
376 with ContainerRunning(self.container):
377- return self.container.update_packages()
378+ return self.container.update_packages(new_locale)
379 except RuntimeError as e:
380 return handle_runtime_error(e)
381
382
383=== modified file 'python/libertine/LxcContainer.py'
384--- python/libertine/LxcContainer.py 2017-01-05 15:25:21 +0000
385+++ python/libertine/LxcContainer.py 2017-01-18 14:37:20 +0000
386@@ -179,11 +179,6 @@
387 _dump_lxc_log(result.logfile)
388 raise RuntimeError(result.error)
389
390- if self.run_in_container("mountpoint -q /tmp/.X11-unix") == 0:
391- self.run_in_container("umount /tmp/.X11-unix")
392- if self.run_in_container("mountpoint -q /usr/lib/locale") == 0:
393- self.run_in_container("umount -l /usr/lib/locale")
394-
395 def stop_container(self):
396 if self.lxc_manager_interface:
397 self.lxc_manager_interface.operation_stop(self.container_id)
398@@ -194,14 +189,14 @@
399 cmd_args = shlex.split(command_string)
400 return self.container.attach_wait(lxc.attach_run_command, cmd_args)
401
402- def update_packages(self):
403+ def update_packages(self, update_locale=False):
404 if self.timezone_needs_update():
405 self.run_in_container("bash -c \'echo \"{}\" >/etc/timezone\'".format(
406 self.host_info.get_host_timezone()))
407 self.run_in_container("rm -f /etc/localtime")
408 self.run_in_container("dpkg-reconfigure -f noninteractive tzdata")
409
410- return super().update_packages()
411+ return super().update_packages(update_locale)
412
413 def destroy_libertine_container(self):
414 if not self.container.defined:
415@@ -265,6 +260,8 @@
416 self.destroy_libertine_container()
417 return False
418
419+ self.update_locale()
420+
421 self.run_in_container("userdel -r ubuntu")
422 self.run_in_container("useradd -u {} -p {} -G sudo {}".format(
423 str(user_id), crypt.crypt(password), str(username)))
424@@ -282,6 +279,8 @@
425 self.destroy_libertine_container()
426 return False
427
428+ super().create_libertine_container()
429+
430 utils.get_logger().info("stopping container ...")
431 self.stop_container()
432
433@@ -334,7 +333,7 @@
434 return
435
436 self.window_manager = self.container.attach(lxc.attach_run_command,
437- utils.setup_window_manager(self.container_id))
438+ self.setup_window_manager())
439
440 # Setup pulse to work inside the container
441 os.environ['PULSE_SERVER'] = utils.get_libertine_lxc_pulse_socket_path()
442
443=== modified file 'python/libertine/LxdContainer.py'
444--- python/libertine/LxdContainer.py 2017-01-05 20:16:25 +0000
445+++ python/libertine/LxdContainer.py 2017-01-18 14:37:20 +0000
446@@ -12,6 +12,7 @@
447 # You should have received a copy of the GNU General Public License along
448 # with this program. If not, see <http://www.gnu.org/licenses/>.
449
450+import contextlib
451 import crypt
452 import dbus
453 import os
454@@ -98,20 +99,6 @@
455
456
457 def _setup_bind_mount_service(container, uid, username):
458- utils.get_logger().info("Creating systemd mount override service")
459- service = '''
460-[Unit]
461-Description=Fix system mounts for libertine
462-
463-[Service]
464-ExecStart=/usr/bin/libertine-lxd-mount-update
465-
466-[Install]
467-WantedBy=multi-user.target
468-'''[1:-1]
469- container.files.put('/etc/systemd/system/libertine-lxd-mount-update.service', service.encode('utf-8'))
470- container.execute(shlex.split('chmod 644 /etc/systemd/system/libertine-lxd-mount-update.service'))
471-
472 utils.get_logger().info("Creating mount update shell script")
473 script = '''
474 #!/bin/sh
475@@ -128,9 +115,6 @@
476 container.files.put('/usr/bin/libertine-lxd-mount-update', script.format(uid=uid, username=username).encode('utf-8'))
477 container.execute(shlex.split('chmod 755 /usr/bin/libertine-lxd-mount-update'))
478
479- utils.get_logger().info("Enabling systemd mount update service")
480- container.execute(shlex.split('systemctl enable libertine-lxd-mount-update.service'))
481-
482
483 def lxd_container(client, container_id):
484 try:
485@@ -174,11 +158,72 @@
486 return LifecycleResult()
487
488
489+def _lxd_save(entity, error, wait=True):
490+ try:
491+ entity.save(wait=wait)
492+ except pylxd.exceptions.LXDAPIException as e:
493+ utils.get_logger().warning('{} {}'.format(error, str(e)))
494+
495+
496+_CONTAINER_DATA_DIRS = ["/usr/share/applications", "/usr/share/icons", "/usr/local/share/applications", "/usr/share/pixmaps"]
497+
498+
499+class RestoreDevice(contextlib.ExitStack):
500+ def __init__(self, container, device):
501+ super().__init__()
502+ self._container = container
503+ self._device = device
504+ self._source = None
505+ self.remove()
506+ self.callback(self.restore)
507+
508+ def remove(self):
509+ if self._device in self._container.devices:
510+ self._source = self._container.devices[self._device]
511+ del self._container.devices[self._device]
512+ _lxd_save(self._container, 'Saving bind mounts for container \'{}\' raised:'.format(self._container.name))
513+
514+ def restore(self):
515+ if self._source is not None:
516+ self._container.devices[self._device] = self._source
517+ _lxd_save(self._container, 'Saving bind mounts for container \'{}\' raised:'.format(self._container.name), False)
518+
519+
520+def _sync_application_dirs_to_host(container):
521+ host_root = utils.get_libertine_container_rootfs_path(container.name)
522+ for container_path in _CONTAINER_DATA_DIRS:
523+ utils.get_logger().info("Syncing applications directory: {}".format(container_path))
524+ os.makedirs(os.path.join(host_root, container_path.lstrip("/")), exist_ok=True)
525+ with RestoreDevice(container, container_path):
526+ # find a list of files within the container
527+ find = subprocess.Popen(shlex.split("lxc exec {} -- find {} -type f".format(container.name, container_path)), stdout=subprocess.PIPE)
528+ stdout, stderr = find.communicate()
529+
530+ if find.returncode == 0:
531+ for filepath in stdout.decode('utf-8').strip().split('\n'):
532+ if filepath:
533+ host_path = os.path.join(host_root, filepath.lstrip("/"))
534+ if not os.path.exists(host_path):
535+ utils.get_logger().debug("Syncing file: {}:{}".format(filepath, host_path))
536+ os.makedirs(os.path.dirname(host_path), exist_ok=True)
537+ with open(host_path, 'wb') as f:
538+ f.write(container.files.get(filepath))
539+
540+
541 def update_bind_mounts(container, config):
542 home_path = os.environ['HOME']
543+ userdata_dir = utils.get_libertine_container_userdata_dir_path(container.name)
544
545 container.devices.clear()
546 container.devices['root'] = {'type': 'disk', 'path': '/'}
547+ container.devices['home'] = {'type': 'disk', 'path': home_path, 'source': userdata_dir}
548+
549+ # applications and icons directories
550+ rootfs_path = utils.get_libertine_container_rootfs_path(container.name)
551+ for data_dir in _CONTAINER_DATA_DIRS:
552+ host_path = "{}{}".format(rootfs_path, data_dir)
553+ os.makedirs(host_path, exist_ok=True)
554+ container.devices[data_dir] = {'type': 'disk', 'path': data_dir, 'source': host_path}
555
556 if os.path.exists(os.path.join(home_path, '.config', 'dconf')):
557 container.devices['dconf'] = {
558@@ -201,6 +246,8 @@
559 path = user_dir[1]
560 else:
561 path = os.path.join(home_path, user_dir[1])
562+ hostpath = os.path.join(userdata_dir, user_dir[1])
563+ os.makedirs(hostpath, exist_ok=True)
564
565 utils.get_logger().debug("Mounting {}:{} in container {}".format(user_dir[0], path, container.name))
566
567@@ -211,11 +258,7 @@
568 'type': 'disk'
569 }
570
571- try:
572- container.save(wait=True)
573- except pylxd.exceptions.LXDAPIException as e:
574- utils.get_logger().warning('Saving bind mounts for container \'{}\' raised: {}'.format(container.name, str(e)))
575- # This is most likely the result of the container currently running
576+ _lxd_save(container, 'Saving bind mounts for container \'{}\' raised:'.format(container.name))
577
578
579 def update_libertine_profile(client):
580@@ -226,12 +269,7 @@
581 profile.devices = _get_devices_map()
582 profile.config['raw.idmap'] = 'both 1000 1000'
583
584- try:
585- profile.save()
586- except pylxd.exceptions.LXDAPIException as e:
587- utils.get_logger().warning('Saving libertine lxd profile raised: {}'.format(str(e)))
588- # This is most likely the result of an older container currently
589- # running and/or containing a conflicting device entry
590+ _lxd_save(profile, 'Saving libertine lxd profile raised:')
591 except pylxd.exceptions.LXDAPIException:
592 utils.get_logger().info('Creating libertine lxd profile.')
593 client.profiles.create('libertine', config={'raw.idmap': 'both 1000 1000'}, devices=_get_devices_map())
594@@ -251,7 +289,6 @@
595
596 self._client = pylxd.Client()
597 self._window_manager = None
598- self.root_path = '{}/containers/{}/rootfs'.format(os.getenv('LXD_DIR', '/var/lib/lxd'), name)
599
600 utils.set_session_dbus_env_var()
601 try:
602@@ -277,19 +314,22 @@
603 utils.get_logger().error("Creating container '{}' failed with code '{}'".format(self._id, create.returncode))
604 return False
605
606- if not self.start_container():
607- utils.get_logger().error("Failed to start container '{}'".format(self._id))
608- self.destroy_libertine_container()
609- return False
610+ self._try_get_container()
611+ _sync_application_dirs_to_host(self._container)
612+ update_bind_mounts(self._container, self._config)
613+
614+ self.update_locale()
615
616 username = os.environ['USER']
617 uid = str(os.getuid())
618 self.run_in_container("userdel -r ubuntu")
619 self.run_in_container("useradd -u {} -U -p {} -G sudo,audio,video {}".format(
620- uid, crypt.crypt(''), username))
621+ uid, crypt.crypt(password or ''), username))
622 self.run_in_container("mkdir -p /home/{}".format(username))
623 self.run_in_container("chown {0}:{0} /home/{0}".format(username))
624
625+ utils.create_libertine_user_data_dir(self._id)
626+
627 _setup_bind_mount_service(self._container, uid, username)
628
629 if multiarch and self.architecture == 'amd64':
630@@ -305,25 +345,34 @@
631 self.destroy_libertine_container()
632 return False
633
634+ super().create_libertine_container()
635+
636 return True
637
638- def update_packages(self):
639+ def update_packages(self, update_locale=False):
640 if not self._timezone_in_sync():
641 utils.get_logger().info("Re-syncing timezones")
642 self.run_in_container("bash -c 'echo \"%s\" > /etc/timezone'" % self._host_info.get_host_timezone())
643 self.run_in_container("rm -f /etc/localtime")
644 self.run_in_container("dpkg-reconfigure -f noninteractive tzdata")
645
646- return super().update_packages()
647+ _sync_application_dirs_to_host(self._container)
648+ update_bind_mounts(self._container, self._config)
649+
650+ return super().update_packages(update_locale)
651
652 def destroy_libertine_container(self):
653 if not self._try_get_container():
654 utils.get_logger().error("No such container '%s'" % self._id)
655 return False
656
657- self.stop_container(wait=True)
658+ if not self.stop_container(wait=True):
659+ utils.get_logger().error("Canceling destruction due to running container")
660+ return False
661+
662 self._container.delete()
663- return True
664+
665+ return self._delete_rootfs()
666
667 def _timezone_in_sync(self):
668 proc = subprocess.Popen(self._lxc_args('cat /etc/timezone'), stdout=subprocess.PIPE)
669@@ -366,7 +415,7 @@
670 return False
671
672 if self._manager:
673- result = LifecycleResult.from_dict(self._manager.operation_stop(self._id))
674+ result = LifecycleResult.from_dict(self._manager.operation_stop(self._id, {'wait': wait}))
675 else:
676 result = lxd_stop(self._container, wait)
677
678@@ -382,7 +431,7 @@
679
680 # FIXME: Remove once window management logic has been moved to the host
681 def _start_window_manager(self, args):
682- args.extend(utils.setup_window_manager(self._id))
683+ args.extend(self.setup_window_manager())
684
685 if 'matchbox-window-manager' in args:
686 pids = self._get_matchbox_pids()
687@@ -404,6 +453,8 @@
688 utils.get_logger().error("Could not get container '{}'".format(self._id))
689 return None
690
691+ requires_remount = self._container.status != 'Running'
692+
693 if self._manager:
694 result = LifecycleResult.from_dict(self._manager.app_start(self._id))
695 else:
696@@ -415,7 +466,10 @@
697 utils.get_logger().error(result.error)
698 return False
699
700- args = self._lxc_args("sudo -E -u {} env PATH={}".format(os.environ['USER'], environ['PATH']), environ)
701+ if requires_remount:
702+ self._container.execute(shlex.split('/usr/bin/libertine-lxd-mount-update'))
703+
704+ args = self._lxc_args("sudo -E -u {} env PATH={}".format(environ['USER'], environ['PATH']), environ)
705
706 self._start_window_manager(args.copy())
707
708
709=== modified file 'python/libertine/lifecycle/ContainerLifecycleService.py'
710--- python/libertine/lifecycle/ContainerLifecycleService.py 2016-12-23 15:46:44 +0000
711+++ python/libertine/lifecycle/ContainerLifecycleService.py 2017-01-18 14:37:20 +0000
712@@ -46,7 +46,7 @@
713 def start(self, container):
714 raise NotImplementedError("Subclasses must implement start(container)")
715
716- def stop(self, container):
717+ def stop(self, container, options={}):
718 raise NotImplementedError("Subclasses must implement stop(container)")
719
720 @dbus.service.method(LIBERTINE_CONTAINER_LIFECYCLE_INTERFACE,
721@@ -55,7 +55,7 @@
722 def app_start(self, container):
723 utils.get_logger().debug("app_start({})".format(container))
724 if self._operations[container] != 0:
725- return LifecycleResult("Libertine container operation already running: cannot launch application.")
726+ return LifecycleResult("Libertine container operation already running: cannot launch application.").to_dict()
727
728 result = self.start(container, True)
729
730@@ -84,7 +84,7 @@
731 def operation_start(self, container):
732 utils.get_logger().debug("operation_start({})".format(container))
733 if self._apps[container] != 0:
734- return LifecycleResult("Application already running in container: cannot run operation.")
735+ return LifecycleResult("Application already running in container: cannot run operation.").to_dict()
736
737 result = self.start(container, False)
738
739@@ -94,15 +94,15 @@
740 return result.to_dict()
741
742 @dbus.service.method(LIBERTINE_CONTAINER_LIFECYCLE_INTERFACE,
743- in_signature='s',
744+ in_signature='sa{ss}',
745 out_signature='a{ss}')
746- def operation_stop(self, container):
747- utils.get_logger().debug("operation_stop({})".format(container))
748+ def operation_stop(self, container, options={}):
749+ utils.get_logger().debug("operation_stop({}, {})".format(container, options))
750 self._operations[container] -= 1
751 result = LifecycleResult()
752
753 if self._operations[container] == 0:
754- result = self.stop(container)
755+ result = self.stop(container, options)
756 del self._operations[container]
757
758 return result.to_dict()
759
760=== modified file 'python/libertine/utils.py'
761--- python/libertine/utils.py 2017-01-05 14:23:21 +0000
762+++ python/libertine/utils.py 2017-01-18 14:37:20 +0000
763@@ -103,6 +103,9 @@
764 if path is None:
765 path = os.path.join(basedir.xdg_data_home, 'libertine-container', 'user-data', container_id)
766
767+ if is_snap_environment():
768+ path = path.replace(os.environ['HOME'], os.getenv('SNAP_USER_COMMON'))
769+
770 return path
771
772
773@@ -163,17 +166,6 @@
774 return os.path.join(get_libertine_runtime_dir(), 'pulse_socket')
775
776
777-def setup_window_manager(container_id, enable_toolbars=False):
778- if os.path.exists(os.path.join(get_libertine_container_rootfs_path(container_id),
779- 'usr', 'bin', 'matchbox-window-manager')):
780- if enable_toolbars:
781- return ['matchbox-window-manager']
782-
783- return ['matchbox-window-manager', '-use_titlebar', 'no']
784- else:
785- return ['compiz']
786-
787-
788 def terminate_window_manager(window_manager):
789 for child in window_manager.children():
790 child.terminate()
791
792=== modified file 'snapcraft.yaml'
793--- snapcraft.yaml 2017-01-05 20:20:33 +0000
794+++ snapcraft.yaml 2017-01-18 14:37:20 +0000
795@@ -1,5 +1,5 @@
796 name: libertine
797-version: 1.5+17.04.20170105.1-0ubuntu1
798+version: "1.5.1"
799 summary: Libertine suite
800 description: |
801 Suite for maintaining deb-based applications in a non-deb environment
802
803=== modified file 'tools/libertine-container-manager'
804--- tools/libertine-container-manager 2017-01-05 14:23:21 +0000
805+++ tools/libertine-container-manager 2017-01-18 14:37:20 +0000
806@@ -34,6 +34,14 @@
807 self.containers_config = ContainersConfig()
808 self.host_info = HostInfo()
809
810+ def _get_updated_locale(self, container_id):
811+ host_locale = self.host_info.get_host_locale()
812+
813+ if host_locale == self.containers_config.get_container_locale(container_id):
814+ return None
815+ else:
816+ return host_locale
817+
818 def create(self, args):
819 password = None
820
821@@ -71,7 +79,7 @@
822 if not args.name:
823 args.name = "Ubuntu \'" + (self.host_info.get_distro_codename(args.distro) or args.distro) + "\'"
824
825- if container_type == "lxc":
826+ if container_type == "lxc" or container_type == "lxd":
827 if args.password:
828 password = args.password
829 elif sys.stdin.isatty():
830@@ -88,6 +96,7 @@
831 self.containers_config.update_container_multiarch_support(args.id, multiarch)
832
833 try:
834+ self.containers_config.update_container_locale(args.id, self.host_info.get_host_locale())
835 container = LibertineContainer(args.id)
836 self.containers_config.update_container_install_status(args.id, "installing")
837 if not container.create_libertine_container(password, args.multiarch):
838@@ -96,6 +105,9 @@
839 sys.exit(1)
840 except Exception as e:
841 libertine.utils.get_logger().error("Failed to create container: '{}'".format(str(e)))
842+ if container:
843+ container.destroy_libertine_container()
844+
845 self.containers_config.delete_container(args.id)
846 sys.exit(1)
847
848@@ -139,7 +151,7 @@
849 else:
850 self.containers_config.add_new_package(container_id, package)
851
852- container = LibertineContainer(container_id)
853+ container = LibertineContainer(container_id, self.containers_config)
854
855 self.containers_config.update_package_install_status(container_id, package, "installing")
856 if not container.install_package(args.package, args.no_dialog):
857@@ -191,14 +203,18 @@
858
859 def update(self, args):
860 container_id = self.containers_config.check_container_id(args.id)
861+ new_locale = self._get_updated_locale(container_id)
862
863 container = LibertineContainer(container_id)
864
865 self.containers_config.update_container_install_status(container_id, "updating")
866- if not container.update_libertine_container():
867+ if not container.update_libertine_container(new_locale):
868 self.containers_config.update_container_install_status(container_id, "ready")
869 sys.exit(1)
870
871+ if new_locale:
872+ self.containers_config.update_container_locale(container_id, new_locale)
873+
874 self.containers_config.update_container_install_status(container_id, "ready")
875
876 def list(self, args):
877@@ -454,7 +470,8 @@
878 # Handle the update command and its options
879 parser_update = subparsers.add_parser(
880 'update',
881- help=("Update the packages in the Libertine container."))
882+ help=("Update the packages in the Libertine container. Also updates the container's "
883+ "locale and installs necessary language packs if the host's locale has changed."))
884 parser_update.add_argument(
885 '-i', '--id',
886 help=("Container identifier. Default container is used if omitted."))
887
888=== modified file 'tools/libertine-container-manager.1'
889--- tools/libertine-container-manager.1 2016-12-07 21:24:16 +0000
890+++ tools/libertine-container-manager.1 2017-01-18 14:37:20 +0000
891@@ -52,7 +52,7 @@
892 Searches the apt cache inside an existing Libertine container for matches based on the given search string.
893 .TP
894 .B libertine-container-manager update [options]
895-Updates the packages inside an existing Libertine container.
896+Updates the packages inside an existing Libertine container. Also updates the container's locale and installs necessary language packs if the host's locale has changed.
897 .TP
898 .B libertine-container-manager list [options]
899 Lists all existing Libertine containers.
900
901=== modified file 'tools/libertine-lxc-manager'
902--- tools/libertine-lxc-manager 2017-01-05 19:50:46 +0000
903+++ tools/libertine-lxc-manager 2017-01-18 14:37:20 +0000
904@@ -55,7 +55,7 @@
905
906 return LifecycleResult()
907
908- def stop(self, container_id):
909+ def stop(self, container_id, options={}):
910 container = libertine.LxcContainer.lxc_container(container_id)
911 libertine.LxcContainer.lxc_stop(container)
912
913
914=== modified file 'tools/libertine-lxd-manager'
915--- tools/libertine-lxd-manager 2016-12-21 20:37:57 +0000
916+++ tools/libertine-lxd-manager 2017-01-18 14:37:20 +0000
917@@ -49,8 +49,8 @@
918
919 return LifecycleResult()
920
921- def stop(self, container_id):
922- return libertine.LxdContainer.lxd_stop(libertine.LxdContainer.lxd_container(self._client, container_id), False)
923+ def stop(self, container_id, options={}):
924+ return libertine.LxdContainer.lxd_stop(libertine.LxdContainer.lxd_container(self._client, container_id), options.get('wait', False))
925
926
927 if __name__ == '__main__':

Subscribers

People subscribed via source and target branches