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

Proposed by Christopher Townsend
Status: Merged
Approved by: Larry Price
Approved revision: 139
Merged at revision: 138
Proposed branch: lp:~townsend/libertine/release-1.2.2
Merge into: lp:libertine/trunk
Diff against target: 2202 lines (+838/-865)
17 files modified
debian/changelog (+30/-0)
debian/python3-libertine.install (+2/-0)
debian/rules (+3/-0)
libertine/qml/ExtraArchivesView.qml (+3/-6)
libertine/qml/GenericErrorDialog.qml (+17/-3)
libertine/qml/HomeView.qml (+51/-43)
po/CMakeLists.txt (+0/-3)
python/libertine/ChrootContainer.py (+26/-72)
python/libertine/ContainersConfig.py (+309/-0)
python/libertine/HostInfo.py (+71/-0)
python/libertine/Libertine.py (+17/-44)
python/libertine/LxcContainer.py (+19/-16)
python/libertine/utils.py (+1/-29)
tests/unit/CMakeLists.txt (+11/-7)
tools/libertine-container-manager (+269/-634)
tools/libertine-launch (+8/-8)
tools/libertine-session-bridge (+1/-0)
To merge this branch: bzr merge lp:~townsend/libertine/release-1.2.2
Reviewer Review Type Date Requested Status
Larry Price Approve
Review via email: mp+299464@code.launchpad.net

Commit message

* If we fail to find the host path remove the session path since it would have been created with the socket.
* Only set the LXC log file when the container is about to start. (LP: #1596020)
* Add a new ContainersConfig Python class for managing all things ContainersConfig.json.
* Refactor host information into a new HostInfo class.
* Check if the LXC container is defined before trying to start it.
* Remove dependency on DISPLAY variable and use random string to generate session socket path.
* Prevent showing multiple error dialogs when adding archive fails. (LP: #1594957)
* Only generate translations when manually running `make translations`.
* Ensure /usr/games is in PATH before launching applications. (LP: #1598227)
* Make error details selectable and add clipboard button. (LP: #1598786)
* Use dialog instead of ActionSelectionPopover to address focusing issues when installing packages.
* Verify host kernel has lxc support. (LP: #1599193)
* Set DEBIAN_FRONTEND directly in environment for chroot containers. (LP: #1599246)

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

When creating a container, I get the following error:

```
Traceback (most recent call last):
  File "tools/libertine-container-manager", line 492, in <module>
    args.func(args)
  File "tools/libertine-container-manager", line 51, in create
    container_type = self.host_info.select_container_type_by_kernel()
  File "/home/lrp/Projects/2016/libertine-1.2.2/python/libertine/HostInfo.py", line 25, in select_container_type_by_kernel
    if has_lxc_support():
NameError: name 'has_lxc_support' is not defined
```

Probably missing a `self`? See minor diff comments.

review: Needs Fixing
lp:~townsend/libertine/release-1.2.2 updated
139. By Christopher Townsend

Merged hot fix from lp:libertine.
Fix typo in debian/changelog.

Revision history for this message
Larry Price (larryprice) wrote :

Alright - lgtm!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2016-06-23 14:01:47 +0000
+++ debian/changelog 2016-07-07 20:14:07 +0000
@@ -1,3 +1,33 @@
1libertine (1.2.2-0ubuntu1) UNRELEASED; urgency=medium
2
3 [ Brandon Schaefer ]
4 * If we fail to find the host path remove the session path since it would
5 have been created with the socket.
6
7 [ Chris Townsend ]
8 * Only set the LXC log file when the container is about to start.
9 (LP: #1596020)
10 * Add a new ContainersConfig Python class for managing all things
11 ContainersConfig.json.
12 * Refactor host information into a new HostInfo class.
13 * Check if the LXC container is defined before trying to start it.
14
15 [ Larry Price ]
16 * Remove dependency on DISPLAY variable and use random string to generate
17 session socket path.
18 * Prevent showing multiple error dialogs when adding archive fails.
19 (LP: #1594957)
20 * Only generate translations when manually running `make translations`.
21 * Ensure /usr/games is in PATH before launching applications. (LP: #1598227)
22 * Make error details selectable and add clipboard button. (LP: #1598786)
23 * Use dialog instead of ActionSelectionPopover to address focusing issues
24 when installing packages.
25 * Verify host kernel has lxc support. (LP: #1599193)
26 * Set DEBIAN_FRONTEND directly in environment for chroot containers.
27 (LP: #1599246)
28
29 -- Chris Townsend <christopher.townsend@canonical.com> Thu, 07 Jul 2016 15:08:59 -0400
30
1libertine (1.2.1+16.10.20160623-0ubuntu1) yakkety; urgency=medium31libertine (1.2.1+16.10.20160623-0ubuntu1) yakkety; urgency=medium
232
3 [ Chris Townsend ]33 [ Chris Townsend ]
434
=== modified file 'debian/python3-libertine.install'
--- debian/python3-libertine.install 2015-12-15 15:46:58 +0000
+++ debian/python3-libertine.install 2016-07-07 20:14:07 +0000
@@ -1,4 +1,6 @@
1usr/lib/python*/*/libertine/AppDiscovery.py1usr/lib/python*/*/libertine/AppDiscovery.py
2usr/lib/python*/*/libertine/Libertine.py2usr/lib/python*/*/libertine/Libertine.py
3usr/lib/python*/*/libertine/ContainersConfig.py
4usr/lib/python*/*/libertine/HostInfo.py
3usr/lib/python*/*/libertine/utils.py5usr/lib/python*/*/libertine/utils.py
4usr/lib/python*/*/libertine/__init__.py6usr/lib/python*/*/libertine/__init__.py
57
=== modified file 'debian/rules'
--- debian/rules 2016-06-22 19:52:24 +0000
+++ debian/rules 2016-07-07 20:14:07 +0000
@@ -2,3 +2,6 @@
22
3%:3%:
4 dh $@ --with python3,gir,click4 dh $@ --with python3,gir,click
5
6override_dh_auto_build:
7 dh_auto_build -- all translations
58
=== modified file 'libertine/qml/ExtraArchivesView.qml'
--- libertine/qml/ExtraArchivesView.qml 2016-05-19 17:56:43 +0000
+++ libertine/qml/ExtraArchivesView.qml 2016-07-07 20:14:07 +0000
@@ -126,25 +126,22 @@
126 }126 }
127127
128 function addArchive(archive) {128 function addArchive(archive) {
129 var comp = Qt.createComponent("ContainerManager.qml")129 var worker = Qt.createComponent("ContainerManager.qml").createObject(mainView)
130 worker = comp.createObject(mainView)
131 worker.finishedConfigure.connect(finishedConfigure)130 worker.finishedConfigure.connect(finishedConfigure)
132 worker.error.connect(sendAddError)131 worker.error.connect(sendAddError)
133 error.connect(mainView.error)
134 worker.configureContainer(mainView.currentContainer, containerConfigList.getContainerName(mainView.currentContainer), ["--add-archive", archive])132 worker.configureContainer(mainView.currentContainer, containerConfigList.getContainerName(mainView.currentContainer), ["--add-archive", archive])
135 }133 }
136134
137 function deleteArchive(archive) {135 function deleteArchive(archive) {
138 var comp = Qt.createComponent("ContainerManager.qml")136 var worker = Qt.createComponent("ContainerManager.qml").createObject(mainView)
139 worker = comp.createObject(mainView)
140 worker.finishedConfigure.connect(finishedConfigure)137 worker.finishedConfigure.connect(finishedConfigure)
141 worker.error.connect(sendDeleteError)138 worker.error.connect(sendDeleteError)
142 error.connect(mainView.error)
143 worker.configureContainer(mainView.currentContainer, containerConfigList.getContainerName(mainView.currentContainer), ["--delete-archive", archive])139 worker.configureContainer(mainView.currentContainer, containerConfigList.getContainerName(mainView.currentContainer), ["--delete-archive", archive])
144 }140 }
145141
146 Component.onCompleted: {142 Component.onCompleted: {
147 containerConfigList.configChanged.connect(reloadArchives)143 containerConfigList.configChanged.connect(reloadArchives)
144 error.connect(mainView.error)
148 }145 }
149146
150 Component.onDestruction: {147 Component.onDestruction: {
151148
=== modified file 'libertine/qml/GenericErrorDialog.qml'
--- libertine/qml/GenericErrorDialog.qml 2016-05-10 14:55:15 +0000
+++ libertine/qml/GenericErrorDialog.qml 2016-07-07 20:14:07 +0000
@@ -22,11 +22,25 @@
2222
23Dialog {23Dialog {
24 id: genericErrorDialog24 id: genericErrorDialog
25 property var short_description: null25 property string short_description: ""
26 property var details: null26 property string details: ""
2727
28 title: short_description28 title: short_description
29 text: details29
30 TextEdit {
31 color: UbuntuColors.darkGrey
32 text: details
33 readOnly: true
34 selectByMouse: true
35 wrapMode: TextEdit.WordWrap
36 }
37
38 Button {
39 text: i18n.tr("Copy to Clipboard")
40 onClicked: {
41 Clipboard.push(details)
42 }
43 }
3044
31 Button {45 Button {
32 text: i18n.tr("Dismiss")46 text: i18n.tr("Dismiss")
3347
=== modified file 'libertine/qml/HomeView.qml'
--- libertine/qml/HomeView.qml 2016-06-08 21:36:14 +0000
+++ libertine/qml/HomeView.qml 2016-07-07 20:14:07 +0000
@@ -31,11 +31,11 @@
31 Action {31 Action {
32 id: settingsButton32 id: settingsButton
33 iconName: "settings"33 iconName: "settings"
34 onTriggered: PopupUtils.open(settingsMenu, homeView)34 onTriggered: PopupUtils.open(settingsMenu)
35 },35 },
36 Action {36 Action {
37 iconName: "add"37 iconName: "add"
38 onTriggered: PopupUtils.open(addAppsMenu, homeView)38 onTriggered: PopupUtils.open(addAppsMenu)
39 }39 }
40 ]40 ]
41 }41 }
@@ -98,26 +98,28 @@
9898
99 Component {99 Component {
100 id: settingsMenu100 id: settingsMenu
101 ActionSelectionPopover {101 Dialog {
102 actions: ActionList {102 id: settingsDialog
103 Action {103 __closeOnDismissAreaPress: true
104 text: i18n.tr("Manage Container")104 Button {
105 onTriggered: {105 text: i18n.tr("Manage Container")
106 pageStack.push(Qt.resolvedUrl("ManageContainer.qml"), {currentContainer: currentContainer})106 onTriggered: {
107 }107 PopupUtils.close(settingsDialog)
108 }108 pageStack.push(Qt.resolvedUrl("ManageContainer.qml"), {currentContainer: currentContainer})
109 Action {109 }
110 text: i18n.tr("Container Information")110 }
111 onTriggered: {111 Button {
112 pageStack.push(Qt.resolvedUrl("ContainerInfoView.qml"), {currentContainer: currentContainer})112 text: i18n.tr("Container Information")
113 }113 onTriggered: {
114 }114 PopupUtils.close(settingsDialog)
115 Action {115 pageStack.push(Qt.resolvedUrl("ContainerInfoView.qml"), {currentContainer: currentContainer})
116 text: i18n.tr("Switch Container")116 }
117 onTriggered: {117 }
118 pageStack.pop()118 Button {
119 pageStack.push(Qt.resolvedUrl("ContainersView.qml"))119 text: i18n.tr("Switch Container")
120 }120 onTriggered: {
121 PopupUtils.close(settingsDialog)
122 pageStack.pop()
121 }123 }
122 }124 }
123 }125 }
@@ -125,27 +127,33 @@
125127
126 Component {128 Component {
127 id: addAppsMenu129 id: addAppsMenu
128 ActionSelectionPopover {130 Dialog {
129 id: addAppsActions131 id: addAppsDialog
130 actions: ActionList {132 __closeOnDismissAreaPress: true
131 Action {133
132 text: i18n.tr("Enter package name or Debian file")134 Button {
133 onTriggered: {135 text: i18n.tr("Enter package name or Debian file")
134 PopupUtils.open(enterPackagePopup)136 width: parent.width
135 }137 onClicked: {
136 }138 PopupUtils.close(addAppsDialog)
137 Action {139 PopupUtils.open(enterPackagePopup)
138 text: i18n.tr("Choose Debian package to install")140 }
139 onTriggered: {141 }
140 var packages = containerConfigList.getDebianPackageFiles()142 Button {
141 pageStack.push(Qt.resolvedUrl("DebianPackagePicker.qml"), {packageList: packages}) 143 text: i18n.tr("Choose Debian package to install")
142 }144 width: parent.width
143 }145 onClicked: {
144 Action {146 PopupUtils.close(addAppsDialog)
145 text: i18n.tr("Search archives for a package")147 var packages = containerConfigList.getDebianPackageFiles()
146 onTriggered: {148 pageStack.push(Qt.resolvedUrl("DebianPackagePicker.qml"), {packageList: packages})
147 PopupUtils.open(Qt.resolvedUrl("SearchPackagesDialog.qml"))149 }
148 }150 }
151 Button {
152 text: i18n.tr("Search archives for a package")
153 width: parent.width
154 onClicked: {
155 PopupUtils.close(addAppsDialog)
156 PopupUtils.open(Qt.resolvedUrl("SearchPackagesDialog.qml"))
149 }157 }
150 }158 }
151 }159 }
152160
=== modified file 'po/CMakeLists.txt'
--- po/CMakeLists.txt 2016-02-29 18:07:02 +0000
+++ po/CMakeLists.txt 2016-07-07 20:14:07 +0000
@@ -1,7 +1,6 @@
1set (GETTEXT_PACKAGE "libertine")1set (GETTEXT_PACKAGE "libertine")
22
3intltool_update_potfile(3intltool_update_potfile(
4 ALL
5 UBUNTU_SDK_DEFAULTS4 UBUNTU_SDK_DEFAULTS
6 POTFILES_TEMPLATE POTFILES.in.in5 POTFILES_TEMPLATE POTFILES.in.in
7 COPYRIGHT_HOLDER "Canonical Ltd."6 COPYRIGHT_HOLDER "Canonical Ltd."
@@ -9,14 +8,12 @@
9)8)
109
11intltool_install_translations(10intltool_install_translations(
12 ALL
13 GETTEXT_PACKAGE ${GETTEXT_PACKAGE}11 GETTEXT_PACKAGE ${GETTEXT_PACKAGE}
14)12)
1513
16file(GLOB_RECURSE ALL_POFILES "*.po")14file(GLOB_RECURSE ALL_POFILES "*.po")
1715
18add_custom_target(potfiles16add_custom_target(potfiles
19 ALL
20 SOURCES17 SOURCES
21 POTFILES.in.in18 POTFILES.in.in
22 ${GETTEXT_PACKAGE}.pot19 ${GETTEXT_PACKAGE}.pot
2320
=== modified file 'python/libertine/ChrootContainer.py'
--- python/libertine/ChrootContainer.py 2016-06-15 18:10:05 +0000
+++ python/libertine/ChrootContainer.py 2016-07-07 20:14:07 +0000
@@ -17,6 +17,7 @@
17import shlex17import shlex
18import shutil18import shutil
19import subprocess19import subprocess
20
20from .Libertine import BaseContainer21from .Libertine import BaseContainer
21from . import utils22from . import utils
2223
@@ -53,10 +54,7 @@
5354
54 def run_in_container(self, command_string):55 def run_in_container(self, command_string):
55 cmd_args = shlex.split(command_string)56 cmd_args = shlex.split(command_string)
56 if self.get_container_distro(self.container_id) == "trusty":57 command_prefix = "fakechroot fakeroot chroot " + self.root_path
57 command_prefix = self._build_privileged_proot_cmd()
58 else:
59 command_prefix = "fakechroot fakeroot chroot " + self.root_path
60 args = shlex.split(command_prefix + ' ' + command_string)58 args = shlex.split(command_prefix + ' ' + command_string)
61 cmd = subprocess.Popen(args)59 cmd = subprocess.Popen(args)
62 return cmd.wait()60 return cmd.wait()
@@ -66,15 +64,9 @@
66 shutil.rmtree(container_root)64 shutil.rmtree(container_root)
6765
68 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):66 def create_libertine_container(self, password=None, multiarch=False, verbosity=1):
69 installed_release = self.get_container_distro(self.container_id)
70 architecture = utils.get_host_architecture()
71
72 # Create the actual chroot67 # Create the actual chroot
73 if installed_release == "trusty":68 command_line = "fakechroot fakeroot debootstrap --verbose --variant=fakechroot {} {}".format(
74 command_line = "debootstrap --verbose " + installed_release + " " + self.root_path69 self.installed_release, self.root_path)
75 else:
76 command_line = "fakechroot fakeroot debootstrap --verbose --variant=fakechroot {} {}".format(
77 installed_release, self.root_path)
78 args = shlex.split(command_line)70 args = shlex.split(command_line)
79 cmd = subprocess.Popen(args)71 cmd = subprocess.Popen(args)
80 cmd.wait()72 cmd.wait()
@@ -84,25 +76,24 @@
84 self.destroy_libertine_container()76 self.destroy_libertine_container()
85 return False77 return False
8678
87 # Remove symlinks as they can ill-behaved recursive behavior in the chroot79 # Remove symlinks as they can cause ill-behaved recursive behavior in the chroot
88 if installed_release != "trusty":80 print("Fixing chroot symlinks...")
89 print("Fixing chroot symlinks...")81 os.remove(os.path.join(self.root_path, 'dev'))
90 os.remove(os.path.join(self.root_path, 'dev'))82 os.remove(os.path.join(self.root_path, 'proc'))
91 os.remove(os.path.join(self.root_path, 'proc'))
9283
93 with open(os.path.join(self.root_path, 'usr', 'sbin', 'policy-rc.d'), 'w+') as fd:84 with open(os.path.join(self.root_path, 'usr', 'sbin', 'policy-rc.d'), 'w+') as fd:
94 fd.write("#!/bin/sh\n\n")85 fd.write("#!/bin/sh\n\n")
95 fd.write("while true; do\n")86 fd.write("while true; do\n")
96 fd.write("case \"$1\" in\n")87 fd.write("case \"$1\" in\n")
97 fd.write(" -*) shift ;;\n")88 fd.write(" -*) shift ;;\n")
98 fd.write(" makedev) exit 0;;\n")89 fd.write(" makedev) exit 0;;\n")
99 fd.write(" *) exit 101;;\n")90 fd.write(" *) exit 101;;\n")
100 fd.write("esac\n")91 fd.write("esac\n")
101 fd.write("done\n")92 fd.write("done\n")
102 os.fchmod(fd.fileno(), 0o755)93 os.fchmod(fd.fileno(), 0o755)
10394
104 # Add universe, multiverse, and -updates to the chroot's sources.list95 # Add universe, multiverse, and -updates to the chroot's sources.list
105 if (utils.get_host_architecture() == 'armhf'):96 if (self.architecture == 'armhf'):
106 archive = "deb http://ports.ubuntu.com/ubuntu-ports "97 archive = "deb http://ports.ubuntu.com/ubuntu-ports "
107 else:98 else:
108 archive = "deb http://archive.ubuntu.com/ubuntu "99 archive = "deb http://archive.ubuntu.com/ubuntu "
@@ -110,52 +101,15 @@
110 if verbosity == 1:101 if verbosity == 1:
111 print("Updating chroot's sources.list entries...")102 print("Updating chroot's sources.list entries...")
112 with open(os.path.join(self.root_path, 'etc', 'apt', 'sources.list'), 'a') as fd:103 with open(os.path.join(self.root_path, 'etc', 'apt', 'sources.list'), 'a') as fd:
113 fd.write(archive + installed_release + "-updates main\n")104 fd.write(archive + self.installed_release + "-updates main\n")
114 fd.write(archive + installed_release + " universe\n")105 fd.write(archive + self.installed_release + " universe\n")
115 fd.write(archive + installed_release + "-updates universe\n")106 fd.write(archive + self.installed_release + "-updates universe\n")
116 fd.write(archive + installed_release + " multiverse\n")107 fd.write(archive + self.installed_release + " multiverse\n")
117 fd.write(archive + installed_release + "-updates multiverse\n")108 fd.write(archive + self.installed_release + "-updates multiverse\n")
118109
119 utils.create_libertine_user_data_dir(self.container_id)110 utils.create_libertine_user_data_dir(self.container_id)
120111
121 if installed_release == "trusty":112 if multiarch and self.architecture == 'amd64':
122 print("Additional configuration for Trusty chroot...")
123
124 cmd_line_prefix = self._build_privileged_proot_cmd()
125
126 command_line = cmd_line_prefix + " dpkg-divert --local --rename --add /etc/init.d/systemd-logind"
127 args = shlex.split(command_line)
128 cmd = subprocess.Popen(args).wait()
129
130 command_line = cmd_line_prefix + " dpkg-divert --local --rename --add /sbin/initctl"
131 args = shlex.split(command_line)
132 cmd = subprocess.Popen(args).wait()
133
134 command_line = cmd_line_prefix + " dpkg-divert --local --rename --add /sbin/udevd"
135 args = shlex.split(command_line)
136 cmd = subprocess.Popen(args).wait()
137
138 command_line = cmd_line_prefix + " dpkg-divert --local --rename --add /usr/sbin/rsyslogd"
139 args = shlex.split(command_line)
140 cmd = subprocess.Popen(args).wait()
141
142 command_line = cmd_line_prefix + " ln -s /bin/true /etc/init.d/systemd-logind"
143 args = shlex.split(command_line)
144 cmd = subprocess.Popen(args).wait()
145
146 command_line = cmd_line_prefix + " ln -s /bin/true /sbin/initctl"
147 args = shlex.split(command_line)
148 cmd = subprocess.Popen(args).wait()
149
150 command_line = cmd_line_prefix + " ln -s /bin/true /sbin/udevd"
151 args = shlex.split(command_line)
152 cmd = subprocess.Popen(args).wait()
153
154 command_line = cmd_line_prefix + " ln -s /bin/true /usr/sbin/rsyslogd"
155 args = shlex.split(command_line)
156 cmd = subprocess.Popen(args).wait()
157
158 if multiarch and architecture == 'amd64':
159 if verbosity == 1:113 if verbosity == 1:
160 print("Adding i386 multiarch support...")114 print("Adding i386 multiarch support...")
161 self.run_in_container("dpkg --add-architecture i386")115 self.run_in_container("dpkg --add-architecture i386")
@@ -170,7 +124,7 @@
170 self.destroy_libertine_container()124 self.destroy_libertine_container()
171 return False125 return False
172126
173 if installed_release == "vivid":127 if self.installed_release == "vivid":
174 if verbosity == 1:128 if verbosity == 1:
175 print("Installing the Vivid Stable Overlay PPA...")129 print("Installing the Vivid Stable Overlay PPA...")
176 self.run_in_container("add-apt-repository ppa:ci-train-ppa-service/stable-phone-overlay -y")130 self.run_in_container("add-apt-repository ppa:ci-train-ppa-service/stable-phone-overlay -y")
177131
=== added file 'python/libertine/ContainersConfig.py'
--- python/libertine/ContainersConfig.py 1970-01-01 00:00:00 +0000
+++ python/libertine/ContainersConfig.py 2016-07-07 20:14:07 +0000
@@ -0,0 +1,309 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import fcntl
16import json
17import libertine.utils
18import os
19import sys
20
21
22def read_container_config_file():
23 container_list = {}
24 container_config_file = libertine.utils.get_libertine_database_file_path()
25
26 if (os.path.exists(container_config_file) and
27 os.path.getsize(container_config_file) != 0):
28 with open(container_config_file, 'r') as fd:
29 container_list = json.load(fd)
30
31 return container_list
32
33
34def write_container_config_file(container_list):
35 container_config_file = libertine.utils.get_libertine_database_file_path()
36
37 with open(container_config_file, 'w') as fd:
38 fcntl.lockf(fd, fcntl.LOCK_EX)
39 json.dump(container_list, fd, sort_keys=True, indent=4)
40 fd.write('\n')
41 fcntl.lockf(fd, fcntl.LOCK_UN)
42
43
44class ContainersConfig(object):
45
46 def __init__(self):
47 self.container_list = read_container_config_file()
48
49 if "defaultContainer" in self.container_list:
50 self.default_container_id = self.container_list['defaultContainer']
51 else:
52 self.default_container_id = None
53
54 """
55 Private helper methods
56 """
57 def _get_container_entry(self, container_id):
58 if not self.container_list:
59 return None
60
61 for container in self.container_list['containerList']:
62 if container['id'] == container_id:
63 return container
64
65 return None
66
67 def _get_value_by_key(self, container_id, key):
68 container = self._get_container_entry(container_id)
69
70 if not container or key not in container:
71 return None
72 else:
73 return container[key]
74
75 def _get_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key):
76 for item in self._get_value_by_key(container_id, array_key):
77 if item[object_key] == matcher:
78 return item[key]
79
80 def _set_value_by_key(self, container_id, key, value):
81 container = self._get_container_entry(container_id)
82
83 if not container:
84 return
85
86 if type(value) is str:
87 container[key] = value
88 elif type(value) is dict:
89 if key not in container:
90 container[key] = [value]
91 else:
92 container[key].append(value)
93
94 write_container_config_file(self.container_list)
95
96 def _set_array_object_value_by_key(self, container_id, array_key, object_key, matcher, key, value):
97 container = self._get_container_entry(container_id)
98
99 if not container:
100 return
101
102 for item in container[array_key]:
103 if item[object_key] == matcher:
104 item[key] = value
105 write_container_config_file(self.container_list)
106 return
107
108 def _delete_array_object_by_key_value(self, container_id, array_key, object_key, value):
109 container = self._get_container_entry(container_id)
110
111 if not container:
112 return
113
114 for item in container[array_key]:
115 if item[object_key] == value:
116 container[array_key].remove(item)
117 write_container_config_file(self.container_list)
118 return
119
120 def _test_key_value_exists(self, container_id, key, value=None):
121 key_value = self._get_value_by_key(container_id, key)
122
123 if not key_value:
124 return False
125 elif key == 'id':
126 return True
127 elif key_value == value:
128 return True
129 else:
130 return False
131
132 def _test_array_object_key_value_exists(self, container_id, array_key, object_key, value):
133 array = self._get_value_by_key(container_id, array_key)
134
135 if not array:
136 return False
137
138 for item in array:
139 if item[object_key] == value:
140 return True
141
142 return False
143
144 """
145 Miscellaneous ContainersConfig.json operations
146 """
147 def _find_duplicate_container_entry(self, container_list, container_id):
148 for container in container_list['containerList']:
149 if container['id'] == container_id:
150 return container
151
152 return None
153
154 def merge_container_config_files(self, filepath):
155 merged_json = []
156
157 with open(filepath, 'r') as fd:
158 merge_source = json.load(fd)
159
160 if "containerList" in self.container_list:
161 # Finds any duplicate entries and assumes we want to update the main config
162 # with entries from the merge source.
163 for i, container in enumerate(self.container_list['containerList']):
164 merge_container = self._find_duplicate_container_entry(merge_source, container['id'])
165 if merge_container:
166 self.container_list['containerList'][i] = merge_container
167 merge_source['containerList'].remove(merge_container)
168
169 # Merges in any remaining non-duplicate entries.
170 for container in merge_source['containerList']:
171 self.container_list['containerList'].append(container)
172
173 else:
174 self.container_list = merge_source
175
176 write_container_config_file(self.container_list)
177
178 def check_container_id(self, container_id):
179 if container_id and not self.container_exists(container_id):
180 print("Container id \'%s\' does not exist." % container_id, file=sys.stderr)
181 sys.exit(1)
182 elif not container_id:
183 return self.get_default_container_id()
184
185 return container_id
186
187 def get_default_container_id(self):
188 return self.default_container_id
189
190 def set_default_container_id(self, container_id, write_json=False):
191 self.default_container_id = container_id
192 self.container_list['defaultContainer'] = container_id
193
194 if write_json:
195 write_container_config_file(self.container_list)
196
197 def clear_default_container_id(self, write_json=False):
198 self.default_container_id = None
199 self.container_list.pop('defaultContainer', None)
200
201 if write_json:
202 write_container_config_file(self.container_list)
203
204 """
205 Operations for the container itself.
206 """
207 def add_new_container(self, container_id, container_name, container_type, container_distro):
208 container_obj = {'id': container_id, 'installStatus': 'new', 'type': container_type,
209 'distro': container_distro, 'name': container_name, 'installedApps': []}
210
211 if "defaultContainer" not in self.container_list:
212 self.set_default_container_id(container_id)
213
214 if "containerList" not in self.container_list:
215 self.container_list['containerList'] = [container_obj]
216 else:
217 self.container_list['containerList'].append(container_obj)
218
219 write_container_config_file(self.container_list)
220
221 def delete_container(self, container_id):
222 if not self.container_list:
223 print("Unable to delete container. No containers defined.")
224 sys.exit(1)
225
226 container = self._get_container_entry(container_id)
227
228 self.container_list['containerList'].remove(container)
229
230 # Set a new defaultContainer if the current default is being deleted.
231 if self.container_list['defaultContainer'] == container_id and self.container_list['containerList']:
232 self.set_default_container_id(self.container_list['containerList'][0]['id'])
233 # Remove the defaultContainer if there are no more containers left.
234 elif not self.container_list['containerList']:
235 self.clear_default_container_id()
236
237 write_container_config_file(self.container_list)
238
239 def update_container_install_status(self, container_id, new_status):
240 self._set_value_by_key(container_id, 'installStatus', new_status)
241
242 def container_exists(self, container_id):
243 return self._test_key_value_exists(container_id, 'id')
244
245 def update_container_multiarch_support(self, container_id, multiarch):
246 if multiarch == 'enabled' and libertine.utils.get_host_architecture() == 'i386':
247 multiarch = 'disabled'
248
249 self._set_value_by_key(container_id, 'multiarch', multiarch)
250
251 def get_container_multiarch_support(self, container_id):
252 multiarch_support = self._get_value_by_key(container_id, 'multiarch')
253
254 if multiarch_support == None:
255 return 'disabled'
256 else:
257 return multiarch_support
258
259 """
260 Operations for archive (PPA) maintenance in a Libertine container.
261 """
262 def add_container_archive(self, container_id, archive_name):
263 archive_obj = {'archiveName': archive_name, 'archiveStatus': 'new'}
264 self._set_value_by_key(container_id, 'extraArchives', archive_obj)
265
266 def delete_container_archive(self, container_id, archive_name):
267 self._delete_array_object_by_key_value(container_id, 'extraArchives',
268 'archiveName', archive_name)
269
270 def update_archive_install_status(self, container_id, archive_name, new_status):
271 self._set_array_object_value_by_key(container_id, 'extraArchives', 'archiveName',
272 archive_name, 'archiveStatus', new_status)
273
274 def archive_exists(self, container_id, archive_name):
275 return self._test_array_object_key_value_exists(container_id, 'extraArchives', 'archiveName',
276 archive_name)
277
278 """
279 Operations for package maintenance in a Libertine container.
280 """
281 def add_new_package(self, container_id, package_name):
282 package_obj = {'packageName': package_name, 'appStatus': 'new'}
283 self._set_value_by_key(container_id, 'installedApps', package_obj)
284
285 def delete_package(self, container_id, package_name):
286 self._delete_array_object_by_key_value(container_id, 'installedApps',
287 'packageName', package_name)
288
289 def update_package_install_status(self, container_id, package_name, new_status):
290 self._set_array_object_value_by_key(container_id, 'installedApps', 'packageName',
291 package_name, 'appStatus', new_status)
292
293 def get_package_install_status(self, container_id, package_name):
294 return self._get_array_object_value_by_key(container_id, 'installedApps', 'packageName',
295 package_name, 'appStatus')
296
297 def package_exists(self, container_id, package_name):
298 return self._test_array_object_key_value_exists(container_id, 'installedApps', 'packageName',
299 package_name)
300
301 """
302 Fetcher functions for various configuration information.
303 """
304 def get_container_distro(self, container_id):
305 return self._get_value_by_key(container_id, 'distro')
306
307 def get_container_type(self, container_id):
308 return self._get_value_by_key(container_id, 'type')
309
0310
=== added file 'python/libertine/HostInfo.py'
--- python/libertine/HostInfo.py 1970-01-01 00:00:00 +0000
+++ python/libertine/HostInfo.py 2016-07-07 20:14:07 +0000
@@ -0,0 +1,71 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15import lsb_release
16import platform
17import subprocess
18
19from distro_info import UbuntuDistroInfo
20
21
22class HostInfo(object):
23
24 def select_container_type_by_kernel(self):
25 if self.has_lxc_support():
26 return "lxc"
27 else:
28 return "chroot"
29
30 def has_lxc_support(self):
31 kernel_release = platform.release().split('.')
32 return int(kernel_release[0]) >= 4 or (int(kernel_release[0]) == 3 and int(kernel_release[1]) >= 13)
33
34 def get_host_distro_release(self):
35 distinfo = lsb_release.get_distro_information()
36
37 return distinfo.get('CODENAME', 'n/a')
38
39 def is_distro_valid(self, distro, force):
40 if force:
41 return UbuntuDistroInfo().valid(distro)
42
43 if distro == self.get_host_distro_release():
44 return True
45
46 supported_distros = UbuntuDistroInfo().supported()
47
48 try:
49 supported_distros.index(distro)
50 except ValueError:
51 return False
52
53 return True
54
55 def get_distro_codename(self, distro):
56 ubuntu_distro_info = UbuntuDistroInfo()
57
58 for row in ubuntu_distro_info._rows:
59 if row['series'] == distro:
60 return row['codename']
61
62 return None
63
64 def get_host_architecture(self):
65 dpkg = subprocess.Popen(['dpkg', '--print-architecture'],
66 stdout=subprocess.PIPE,
67 universal_newlines=True)
68 if dpkg.wait() != 0:
69 parser.error("Failed to determine the local architecture.")
70
71 return dpkg.stdout.read().strip()
072
=== modified file 'python/libertine/Libertine.py'
--- python/libertine/Libertine.py 2016-06-14 20:05:24 +0000
+++ python/libertine/Libertine.py 2016-07-07 20:14:07 +0000
@@ -16,30 +16,12 @@
16from gi.repository import Libertine16from gi.repository import Libertine
17import abc17import abc
18import contextlib18import contextlib
19import json
20import libertine.utils19import libertine.utils
21import os20import os
22import shutil21import shutil
2322
2423from libertine.ContainersConfig import ContainersConfig
25def get_container_type(container_id):24from libertine.HostInfo import HostInfo
26 """
27 Retrieves the type of container for a given container ID.
28 :param container_id: The Container ID to search for.
29 """
30 try:
31 with open(libertine.utils.get_libertine_database_file_path()) as fd:
32 container_list = json.load(fd)
33
34 for container in container_list["containerList"]:
35 if container["id"] == container_id:
36 return container["type"]
37
38 except FileNotFoundError:
39 pass
40
41 # Return lxc as the default container type
42 return "lxc"
4325
4426
45def apt_args_for_verbosity_level(verbosity):27def apt_args_for_verbosity_level(verbosity):
@@ -175,10 +157,9 @@
175157
176 return ret158 return ret
177 else:159 else:
178 cmd = apt_command_prefix(verbosity) + " install '" + package_name + "'"
179 if readline:160 if readline:
180 cmd = "env DEBIAN_FRONTEND=readline " + cmd161 os.environ['DEBIAN_FRONTEND'] = 'readline'
181 return self.run_in_container(cmd) == 0162 return self.run_in_container(apt_command_prefix(verbosity) + " install '" + package_name + "'") == 0
182163
183 def configure_command(self, command, *args, verbosity=1):164 def configure_command(self, command, *args, verbosity=1):
184 """165 """
@@ -207,21 +188,6 @@
207 elif command == 'delete-archive':188 elif command == 'delete-archive':
208 return self.run_in_container("add-apt-repository -y -r " + args[0])189 return self.run_in_container("add-apt-repository -y -r " + args[0])
209190
210 def get_container_distro(self, container_id):
211 """
212 Retrieves the distro code name for a given container ID.
213
214 :param container_id: The Container ID to search for.
215 """
216 with open(libertine.utils.get_libertine_database_file_path()) as fd:
217 container_list = json.load(fd)
218
219 for container in container_list["containerList"]:
220 if container["id"] == container_id:
221 return container["distro"]
222
223 return ""
224
225 @property191 @property
226 def name(self):192 def name(self):
227 """193 """
@@ -281,9 +247,9 @@
281 """247 """
282 super().__init__()248 super().__init__()
283249
284 container_type = get_container_type(container_id)250 container_type = ContainersConfig().get_container_type(container_id)
285251
286 if container_type == "lxc":252 if container_type == None or container_type == "lxc":
287 from libertine.LxcContainer import LibertineLXC253 from libertine.LxcContainer import LibertineLXC
288 self.container = LibertineLXC(container_id)254 self.container = LibertineLXC(container_id)
289 elif container_type == "chroot":255 elif container_type == "chroot":
@@ -320,6 +286,9 @@
320 """286 """
321 Creates the container.287 Creates the container.
322 """288 """
289 self.container.architecture = HostInfo().get_host_architecture()
290 self.container.installed_release = ContainersConfig().get_container_distro(self.container_id)
291
323 return self.container.create_libertine_container(password, multiarch, verbosity)292 return self.container.create_libertine_container(password, multiarch, verbosity)
324293
325 def update_libertine_container(self, verbosity=1):294 def update_libertine_container(self, verbosity=1):
@@ -351,10 +320,10 @@
351 """320 """
352 try:321 try:
353 with ContainerRunning(self.container):322 with ContainerRunning(self.container):
354 cmd = apt_command_prefix(verbosity) + " purge '" + package_name + "'"
355 if readline:323 if readline:
356 cmd = "env DEBIAN_FRONTEND=readline " + cmd324 os.environ['DEBIAN_FRONTEND'] = 'readline'
357 if self.container.run_in_container(cmd) != 0:325
326 if self.container.run_in_container(apt_command_prefix(verbosity) + " purge '" + package_name + "'") != 0:
358 return False327 return False
359 return self.container.run_in_container(apt_command_prefix(verbosity) + "autoremove --purge") == 0328 return self.container.run_in_container(apt_command_prefix(verbosity) + "autoremove --purge") == 0
360 except RuntimeError as e:329 except RuntimeError as e:
@@ -380,7 +349,11 @@
380 :param app_exec_line: the application exec line as passed in by349 :param app_exec_line: the application exec line as passed in by
381 ubuntu-app-launch350 ubuntu-app-launch
382 """351 """
383 if libertine.utils.container_exists(self.container.container_id):352 if ContainersConfig().container_exists(self.container.container_id):
353 # Update $PATH as necessary
354 if '/usr/games' not in os.environ['PATH']:
355 os.environ['PATH'] = os.environ['PATH'] + ":/usr/games"
356
384 self.container.launch_application(app_exec_line)357 self.container.launch_application(app_exec_line)
385 else:358 else:
386 raise RuntimeError("Container with id %s does not exist." % self.container.container_id)359 raise RuntimeError("Container with id %s does not exist." % self.container.container_id)
387360
=== modified file 'python/libertine/LxcContainer.py'
--- python/libertine/LxcContainer.py 2016-06-22 16:26:15 +0000
+++ python/libertine/LxcContainer.py 2016-07-07 20:14:07 +0000
@@ -18,6 +18,7 @@
18import psutil18import psutil
19import shlex19import shlex
20import subprocess20import subprocess
21import sys
21import tempfile22import tempfile
2223
23from .Libertine import BaseContainer24from .Libertine import BaseContainer
@@ -85,11 +86,6 @@
85 self.container_type = "lxc"86 self.container_type = "lxc"
86 self.container = lxc_container(container_id)87 self.container = lxc_container(container_id)
8788
88 if self.container.defined:
89 self.lxc_log_file = os.path.join(tempfile.mkdtemp(), 'lxc-start.log')
90 self.container.append_config_item("lxc.logfile", self.lxc_log_file)
91 self.container.append_config_item("lxc.logpriority", "3")
92
93 def is_running(self):89 def is_running(self):
94 return self.container.running90 return self.container.running
9591
@@ -105,7 +101,11 @@
105 return True101 return True
106102
107 def start_container(self):103 def start_container(self):
104 if not self.container.defined:
105 raise RuntimeError("Container %s is not valid" % self.container_id)
106
108 if not self.container.running:107 if not self.container.running:
108 self._set_lxc_log()
109 if not self.container.start():109 if not self.container.start():
110 self._dump_lxc_log()110 self._dump_lxc_log()
111 raise RuntimeError("Container failed to start")111 raise RuntimeError("Container failed to start")
@@ -147,8 +147,6 @@
147 if password is None:147 if password is None:
148 return False148 return False
149149
150 installed_release = self.get_container_distro(self.container_id)
151
152 username = os.environ['USER']150 username = os.environ['USER']
153 user_id = os.getuid()151 user_id = os.getuid()
154 group_id = os.getgid()152 group_id = os.getgid()
@@ -177,13 +175,10 @@
177175
178 utils.create_libertine_user_data_dir(self.container_id)176 utils.create_libertine_user_data_dir(self.container_id)
179177
180 # Figure out the host architecture
181 architecture = utils.get_host_architecture()
182
183 if not self.container.create("download", 0,178 if not self.container.create("download", 0,
184 {"dist": "ubuntu",179 {"dist": "ubuntu",
185 "release": installed_release,180 "release": self.installed_release,
186 "arch": architecture}):181 "arch": self.architecture}):
187 print("Failed to create container")182 print("Failed to create container")
188 return False183 return False
189184
@@ -202,7 +197,7 @@
202 self.run_in_container("useradd -u {} -p {} -G sudo {}".format(197 self.run_in_container("useradd -u {} -p {} -G sudo {}".format(
203 str(user_id), crypt.crypt(password), str(username)))198 str(user_id), crypt.crypt(password), str(username)))
204199
205 if multiarch and architecture == 'amd64':200 if multiarch and self.architecture == 'amd64':
206 if verbosity == 1:201 if verbosity == 1:
207 print("Adding i386 multiarch support...")202 print("Adding i386 multiarch support...")
208 self.run_in_container("dpkg --add-architecture i386")203 self.run_in_container("dpkg --add-architecture i386")
@@ -308,7 +303,15 @@
308 data = libertine_lxc_mgr_sock.recv(1024)303 data = libertine_lxc_mgr_sock.recv(1024)
309 libertine_lxc_mgr_sock.close()304 libertine_lxc_mgr_sock.close()
310305
306 def _set_lxc_log(self):
307 self.lxc_log_file = os.path.join(tempfile.mkdtemp(), 'lxc-start.log')
308 self.container.append_config_item("lxc.logfile", self.lxc_log_file)
309 self.container.append_config_item("lxc.logpriority", "3")
310
311 def _dump_lxc_log(self):311 def _dump_lxc_log(self):
312 with open(self.lxc_log_file, 'r') as fd:312 try:
313 for line in fd:313 with open(self.lxc_log_file, 'r') as fd:
314 print(line.lstrip())314 for line in fd:
315 print(line.lstrip())
316 except Exception as ex:
317 print("Could not open LXC log file: %s" % ex, file=sys.stderr)
315318
=== modified file 'python/libertine/utils.py'
--- python/libertine/utils.py 2016-06-23 13:27:26 +0000
+++ python/libertine/utils.py 2016-07-07 20:14:07 +0000
@@ -16,9 +16,7 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19import json
20import os19import os
21import psutil
22import shlex20import shlex
23import subprocess21import subprocess
24import xdg.BaseDirectory as basedir22import xdg.BaseDirectory as basedir
@@ -28,22 +26,6 @@
28from gi.repository import Libertine26from gi.repository import Libertine
2927
3028
31def container_exists(container_id):
32 container_config_file_path = get_libertine_database_file_path()
33
34 if (os.path.exists(container_config_file_path) and
35 os.path.getsize(container_config_file_path) != 0):
36 with open(get_libertine_database_file_path()) as fd:
37 container_list = json.load(fd)
38
39 if container_list:
40 for container in container_list['containerList']:
41 if container['id'] == container_id:
42 return True
43
44 return False
45
46
47def get_libertine_container_rootfs_path(container_id):29def get_libertine_container_rootfs_path(container_id):
48 path = Libertine.container_path(container_id)30 path = Libertine.container_path(container_id)
4931
@@ -97,16 +79,6 @@
97 return os.path.join(get_user_runtime_dir(), 'libertine')79 return os.path.join(get_user_runtime_dir(), 'libertine')
9880
9981
100def get_host_architecture():
101 dpkg = subprocess.Popen(['dpkg', '--print-architecture'],
102 stdout=subprocess.PIPE,
103 universal_newlines=True)
104 if dpkg.wait() != 0:
105 parser.error("Failed to determine the local architecture.")
106
107 return dpkg.stdout.read().strip()
108
109
110def get_common_xdg_directories():82def get_common_xdg_directories():
111 return ['Documents', 'Music', 'Pictures', 'Videos', 'Downloads']83 return ['Documents', 'Music', 'Pictures', 'Videos', 'Downloads']
11284
@@ -167,4 +139,4 @@
167 gdbus_cmd = ("gdbus emit --session --object-path %s --signal %s %s" %139 gdbus_cmd = ("gdbus emit --session --object-path %s --signal %s %s" %
168 (scopes_object_path, invalidate_signal, libertine_scope_id))140 (scopes_object_path, invalidate_signal, libertine_scope_id))
169141
170 subprocess.Popen(shlex.split(gdbus_cmd))142 subprocess.Popen(shlex.split(gdbus_cmd), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
171143
=== modified file 'tests/unit/CMakeLists.txt'
--- tests/unit/CMakeLists.txt 2015-12-21 21:02:33 +0000
+++ tests/unit/CMakeLists.txt 2016-07-07 20:14:07 +0000
@@ -44,10 +44,14 @@
44 ENVIRONMENT44 ENVIRONMENT
45 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")45 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")
4646
47add_test(test_libertine_launch47set(DISABLED 1)
48 "/usr/bin/python3" "-m" "testtools.run" "libertine_launch_tests"48
49)49if (NOT DISABLED)
50set_tests_properties(test_libertine_launch50 add_test(test_libertine_launch
51 PROPERTIES51 "/usr/bin/python3" "-m" "testtools.run" "libertine_launch_tests"
52 ENVIRONMENT52 )
53 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")53 set_tests_properties(test_libertine_launch
54 PROPERTIES
55 ENVIRONMENT
56 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR}")
57endif()
5458
=== modified file 'tools/libertine-container-manager'
--- tools/libertine-container-manager 2016-06-20 15:15:38 +0000
+++ tools/libertine-container-manager 2016-07-07 20:14:07 +0000
@@ -17,637 +17,270 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19import argparse19import argparse
20import fcntl
21import json
22import libertine.utils20import libertine.utils
23import lsb_release
24import getpass21import getpass
25import os22import os
26import platform
27import sys23import sys
2824
29from apt.debfile import DebPackage25from apt.debfile import DebPackage
30from distro_info import UbuntuDistroInfo, DistroDataOutdated
31from libertine import LibertineContainer26from libertine import LibertineContainer
3227from libertine.ContainersConfig import ContainersConfig
3328from libertine.HostInfo import HostInfo
34def find_duplicate_container_entry(container_list, container_id):29
35 for container in container_list['containerList']:30
36 if container['id'] == container_id:31class LibertineContainerManager(object):
37 return container32
3833 def __init__(self):
39 return None34 self.containers_config = ContainersConfig()
4035 self.host_info = HostInfo()
4136
42def merge_container_config_files(filepath):37 def create(self, args):
43 merged_json = []38 password = None
44 main_config = read_container_config_file()39
4540 if args.distro and not self.host_info.is_distro_valid(args.distro, args.force):
46 with open(filepath, 'r') as fd:41 print("Invalid distro %s" % args.distro, file=sys.stderr)
47 merge_source = json.load(fd)42 sys.exit(1)
4843
49 if "containerList" in main_config:44 if args.id and self.containers_config.container_exists(args.id):
50 # Finds any duplicate entries and assumes we want to update the main config45 print("Container id \'%s\' is already used." % args.id, file=sys.stderr)
51 # with entries from the merge source.46 sys.exit(1)
52 for i, container in enumerate(main_config['containerList']):47 elif not args.id:
53 merge_container = find_duplicate_container_entry(merge_source, container['id'])48 args.id = get_unique_container_id(distro)
54 if merge_container:49
55 main_config['containerList'][i] = merge_container50 if not args.type:
56 merge_source['containerList'].remove(merge_container)51 container_type = self.host_info.select_container_type_by_kernel()
5752 else:
58 # Merges in any remaining non-duplicate entries.53 if args.type == 'lxc' and not self.host_info.has_lxc_support():
59 for container in merge_source['containerList']:54 print("System kernel does not support lxc type containers. "
60 main_config['containerList'].append(container)55 "Please either use chroot or omit the -t option.")
6156 sys.exit(1)
62 else:57 container_type = args.type
63 main_config = merge_source58
6459 if not args.distro:
65 write_container_config_file(main_config)60 args.distro = self.host_info.get_host_distro_release()
6661 elif container_type == "chroot":
6762 host_distro = self.host_info.get_host_distro_release()
68def read_container_config_file():63
69 container_list = {}64 if args.distro != host_distro:
70 container_config_file = libertine.utils.get_libertine_database_file_path()65 print("The container distribution needs to match the host ditribution for chroot"
7166 " based containers. Please either use \'%s\' or omit the -d/--distro option."
72 if (os.path.exists(container_config_file) and67 % host_distro)
73 os.path.getsize(container_config_file) != 0):68 sys.exit(1)
74 with open(container_config_file, 'r') as fd:69
75 container_list = json.load(fd)70 if not args.name:
7671 args.name = "Ubuntu \'" + self.host_info.get_distro_codename(args.distro) + "\'"
77 return container_list72
7873 if container_type == "lxc":
7974 if args.password:
80def write_container_config_file(container_list):75 password = args.password
81 container_config_file = libertine.utils.get_libertine_database_file_path()76 elif sys.stdin.isatty():
8277 print("Your user password is required for creating a Libertine container.")
83 with open(container_config_file, 'w') as fd:78 password = getpass.getpass()
84 fcntl.lockf(fd, fcntl.LOCK_EX)79 else:
85 json.dump(container_list, fd, sort_keys=True, indent=4)80 password = sys.stdin.readline().rstrip()
86 fd.write('\n')81
87 fcntl.lockf(fd, fcntl.LOCK_UN)82 self.containers_config.add_new_container(args.id, args.name, container_type, args.distro)
8883
89
90def get_default_container_id():
91 default_container_id = None
92
93 container_list = read_container_config_file()
94
95 if "defaultContainer" in container_list:
96 default_container_id = container_list['defaultContainer']
97
98 return default_container_id
99
100
101def select_container_type():
102 kernel_release = platform.release().split('.')
103
104 if int(kernel_release[0]) >= 4:
105 return "lxc"
106 elif int(kernel_release[0]) == 3 and int(kernel_release[1]) >= 13:
107 return "lxc"
108 else:
109 return "chroot"
110
111
112def get_host_distro_release():
113 distinfo = lsb_release.get_distro_information()
114
115 return distinfo.get('CODENAME', 'n/a')
116
117
118def is_distro_valid(distro, force):
119 if force:
120 return UbuntuDistroInfo().valid(distro)
121
122 if distro == get_host_distro_release():
123 return True
124
125 supported_distros = UbuntuDistroInfo().supported()
126
127 try:
128 supported_distros.index(distro)
129 except ValueError:
130 return False
131
132 return True
133
134
135def get_distro_codename(distro):
136 ubuntu_distro_info = UbuntuDistroInfo()
137
138 for row in ubuntu_distro_info._rows:
139 if row['series'] == distro:
140 return row['codename']
141
142 return None
143
144
145def update_container_install_status(container_id, new_status):
146 container_list = read_container_config_file()
147
148 for container in container_list['containerList']:
149 if container['id'] == container_id:
150 container['installStatus'] = new_status
151
152 write_container_config_file(container_list)
153 break
154
155
156def update_container_multiarch_support(container_id, multiarch):
157 container_list = read_container_config_file()
158
159 if multiarch == 'enabled' and libertine.utils.get_host_architecture() == 'i386':
160 multiarch = 'disabled'
161
162 for container in container_list['containerList']:
163 if container['id'] == container_id:
164 container['multiarch'] = multiarch
165
166 write_container_config_file(container_list)
167 break
168
169
170def get_container_multiarch_support(container_id):
171 container_list = read_container_config_file()
172
173 for container in container_list['containerList']:
174 if container['id'] == container_id:
175 if not 'multiarch' in container:
176 return 'disabled'
177 else:
178 return container['multiarch']
179
180
181def update_archive_install_status(container_id, archive_name, new_status):
182 container_list = read_container_config_file()
183
184 for container in container_list['containerList']:
185 if container['id'] == container_id:
186 for archive in container['extraArchives']:
187 if archive['archiveName'] == archive_name:
188 archive['archiveStatus'] = new_status
189 write_container_config_file(container_list)
190 return
191
192
193def add_container_archive(container_id, archive_name):
194 container_list = read_container_config_file()
195
196 for container in container_list['containerList']:
197 if container['id'] == container_id:
198 archive_obj = {'archiveName': archive_name, 'archiveStatus': 'new'}
199
200 if 'extraArchives' not in container:
201 container['extraArchives'] = [archive_obj]
202 else:
203 container['extraArchives'].append(archive_obj)
204
205 write_container_config_file(container_list)
206 break
207
208
209def delete_container_archive(container_id, archive_name):
210 container_list = read_container_config_file()
211
212 for container in container_list['containerList']:
213 if container['id'] == container_id:
214 for archive in container['extraArchives']:
215 if archive['archiveName'] == archive_name:
216 container['extraArchives'].remove(archive)
217 write_container_config_file(container_list)
218 return
219
220 print("%s does not exist." % archive_name)
221 sys.exit(1)
222
223
224def archive_exists(container_id, archive_name):
225 container_list = read_container_config_file()
226
227 for container in container_list['containerList']:
228 if container['id'] == container_id:
229 if 'extraArchives' not in container:
230 return False
231 else:
232 for archive in container['extraArchives']:
233 if archive['archiveName'] == archive_name:
234 return True
235
236 return False
237
238
239def add_new_container(id, name, type, distro):
240 if not os.path.exists(libertine.utils.get_libertine_database_dir_path()):
241 os.makedirs(libertine.utils.get_libertine_database_dir_path())
242
243 container_list = read_container_config_file()
244
245 container_obj = {'id': id, 'installStatus': 'new', 'type': type,
246 'distro': distro, 'name': name, 'installedApps': []}
247
248 if "defaultContainer" not in container_list:
249 container_list['defaultContainer'] = id
250
251 if "containerList" not in container_list:
252 container_list['containerList'] = [container_obj]
253 else:
254 container_list['containerList'].append(container_obj)
255
256 write_container_config_file(container_list)
257
258
259def delete_container(container_id):
260 container_list = read_container_config_file()
261
262 if not container_list:
263 print("Unable to delete container. No containers defined.")
264 sys.exit(1)
265
266 for container in container_list['containerList']:
267 if container['id'] == container_id:
268 container_list['containerList'].remove(container)
269
270 # Set a new defaultContainer if the current default is being deleted.
271 if container_list['defaultContainer'] == container_id and container_list['containerList']:
272 container_list['defaultContainer'] = container_list['containerList'][0]['id']
273 # Remove the defaultContainer if there are no more containers left.
274 elif not container_list['containerList']:
275 del container_list['defaultContainer']
276
277 write_container_config_file(container_list)
278 break
279
280
281def package_exists(container_id, package_name):
282 container_list = read_container_config_file()
283
284 if not container_list:
285 return False
286
287 for container in container_list['containerList']:
288 if container['id'] == container_id:
289 for package in container['installedApps']:
290 if package['packageName'] == package_name:
291 return True
292
293 return False
294
295
296def update_package_install_status(container_id, package_name, new_status):
297 container_list = read_container_config_file()
298
299 for container in container_list['containerList']:
300 if container['id'] == container_id:
301 for package in container['installedApps']:
302 if package['packageName'] == package_name:
303 package['appStatus'] = new_status
304 write_container_config_file(container_list)
305 return
306
307
308def get_package_install_status(container_id, package_name):
309 container_list = read_container_config_file()
310
311 for container in container_list['containerList']:
312 if container['id'] == container_id:
313 for package in container['installedApps']:
314 if package['packageName'] == package_name:
315 return package['appStatus']
316
317
318def add_new_package(container_id, package_name):
319 container_list = read_container_config_file()
320
321 if not container_list:
322 print("No containers defined. Please create a new container before installing a package.")
323 sys.exit(1)
324
325 for container in container_list['containerList']:
326 if container['id'] == container_id:
327 package_obj = {'packageName': package_name, 'appStatus': 'new'}
328
329 if not container['installedApps']:
330 container['installedApps'] = [package_obj]
331 else:
332 container['installedApps'].append(package_obj)
333
334 write_container_config_file(container_list)
335 break
336
337
338def delete_package(container_id, package_name):
339 container_list = read_container_config_file()
340
341 if not container_list:
342 print("No containers defined. Please create a new container before installing a package.")
343 sys.exit(1)
344
345 for container in container_list['containerList']:
346 if container['id'] == container_id:
347 for package in container['installedApps']:
348 if package['packageName'] == package_name:
349 container['installedApps'].remove(package)
350 write_container_config_file(container_list)
351 return
352
353 print("Package \'%s\' does not exist." % package_name)
354 sys.exit(1)
355
356
357def create(args):
358 password = None
359
360 if args.distro and not is_distro_valid(args.distro, args.force):
361 print("Invalid distro %s" % args.distro, file=sys.stderr)
362 sys.exit(1)
363
364 if args.id and libertine.utils.container_exists(args.id):
365 print("Container id \'%s\' is already used." % args.id, file=sys.stderr)
366 sys.exit(1)
367 elif not args.id:
368 args.id = get_unique_container_id(distro)
369
370 if not args.type:
371 container_type = select_container_type()
372 else:
373 container_type = args.type
374
375 if not args.distro:
376 args.distro = get_host_distro_release()
377 elif container_type == "chroot":
378 host_distro = get_host_distro_release()
379
380 if args.distro != host_distro:
381 print("The container distribution needs to match the host ditribution for chroot"
382 " based containers. Please either use \'%s\' or omit the -d/--distro option."
383 % host_distro)
384 sys.exit(1)
385
386 if not args.name:
387 args.name = "Ubuntu \'" + get_distro_codename(args.distro) + "\'"
388
389 if container_type == "lxc":
390 if args.password:
391 password = args.password
392 elif sys.stdin.isatty():
393 print("Your user password is required for creating a Libertine container.")
394 password = getpass.getpass()
395 else:
396 password = sys.stdin.readline().rstrip()
397
398 add_new_container(args.id, args.name, container_type, args.distro)
399
400 multiarch = 'disabled'
401 if args.multiarch:
402 multiarch = 'enabled'
403 update_container_multiarch_support(args.id, multiarch)
404
405 container = LibertineContainer(args.id)
406 update_container_install_status(args.id, "installing")
407 if not container.create_libertine_container(password, args.multiarch, args.verbosity):
408 delete_container(args.id)
409 sys.exit(1)
410 update_container_install_status(args.id, "ready")
411
412 libertine.utils.refresh_libertine_scope()
413
414
415def destroy_container_by_id(id):
416 container = LibertineContainer(id)
417 update_container_install_status(id, "removing")
418 container.destroy_libertine_container()
419 update_container_install_status(id, "removed")
420 delete_container(id)
421
422
423def destroy(args):
424 if args.id and not libertine.utils.container_exists(args.id):
425 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
426 sys.exit(1)
427 elif not args.id:
428 args.id = get_default_container_id()
429
430 destroy_container_by_id(args.id)
431
432 libertine.utils.refresh_libertine_scope()
433
434
435def install_package(args):
436 if args.id and not libertine.utils.container_exists(args.id):
437 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
438 sys.exit(1)
439 elif not args.id:
440 args.id = get_default_container_id()
441
442 is_debian_package = args.package.endswith('.deb')
443
444 if is_debian_package:
445 if os.path.exists(args.package):
446 package = DebPackage(args.package).pkgname
447 else:
448 print("%s does not exist." % args.package)
449 sys.exit(1)
450 else:
451 package = args.package
452
453 if package_exists(args.id, package):
454 if not is_debian_package:
455 print("Package \'%s\' is already installed." % package)
456 sys.exit(1)
457 else:
458 add_new_package(args.id, package)
459
460 container = LibertineContainer(args.id)
461
462 update_package_install_status(args.id, package, "installing")
463 if not container.install_package(args.package, args.verbosity, args.readline):
464 delete_package(args.id, package)
465 sys.exit(1)
466
467 update_package_install_status(args.id, package, "installed")
468
469 libertine.utils.refresh_libertine_scope()
470
471
472def remove_package_by_name(container_id, package_name, verbosity=1, readline=False):
473 fallback_status = get_package_install_status(container_id, package_name)
474 update_package_install_status(container_id, package_name, "removing")
475
476 container = LibertineContainer(container_id)
477 if not container.remove_package(package_name, verbosity, readline):
478 update_package_install_status(container_id, package_name, fallback_status)
479 return False
480
481 update_package_install_status(container_id, package_name, "removed")
482 delete_package(container_id, package_name)
483
484 return True
485
486
487def remove_package(args):
488 if args.id and not libertine.utils.container_exists(args.id):
489 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
490 sys.exit(1)
491 elif not args.id:
492 args.id = get_default_container_id()
493
494 if get_package_install_status(args.id, args.package) != 'installed':
495 print("Package \'%s\' is not installed." % args.package)
496 sys.exit(1)
497
498 if not remove_package_by_name(args.id, args.package, args.verbosity, args.readline):
499 sys.exit(1)
500
501 libertine.utils.refresh_libertine_scope()
502
503
504def search_cache(args):
505 if args.id and not libertine.utils.container_exists(args.id):
506 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
507 sys.exit(1)
508 elif not args.id:
509 args.id = get_default_container_id()
510
511 container = LibertineContainer(args.id)
512 if container.search_package_cache(args.search_string) is not 0:
513 sys.exit(1)
514
515
516def update(args):
517 if args.id and not libertine.utils.container_exists(args.id):
518 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
519 sys.exit(1)
520 elif not args.id:
521 args.id = get_default_container_id()
522
523 container = LibertineContainer(args.id)
524
525 update_container_install_status(args.id, "updating")
526 if container.update_libertine_container(args.verbosity) is not 0:
527 update_container_install_status(args.id, "ready")
528 sys.exit(1)
529
530 update_container_install_status(args.id, "ready")
531
532
533def list(args):
534 containers = libertine.utils.Libertine.list_containers()
535 for container in containers:
536 print("%s" % container)
537
538
539def list_apps(args):
540 if args.id and not libertine.utils.container_exists(args.id):
541 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
542 sys.exit(1)
543 elif not args.id:
544 args.id = get_default_container_id()
545
546 container = LibertineContainer(args.id)
547 print(container.list_app_launchers(use_json=args.json))
548
549
550def exec(args):
551 if args.id and not libertine.utils.container_exists(args.id):
552 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
553 sys.exit(1)
554 elif not args.id:
555 args.id = get_default_container_id()
556
557 container = LibertineContainer(args.id)
558
559 if not container.exec_command(args.command):
560 sys.exit(1)
561
562
563def delete_archive_by_name(container_id, archive_name):
564 update_archive_install_status(container_id, archive_name, 'removing')
565 if LibertineContainer(container_id).configure_command('delete-archive', archive_name) is not 0:
566 return False
567 delete_container_archive(container_id, archive_name)
568 return True
569
570
571def configure(args):
572 if args.id and not libertine.utils.container_exists(args.id):
573 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)
574 sys.exit(1)
575 elif not args.id:
576 args.id = get_default_container_id()
577
578 container = LibertineContainer(args.id)
579
580 if args.multiarch and libertine.utils.get_host_architecture() == 'amd64':
581 multiarch = 'disabled'84 multiarch = 'disabled'
582 if args.multiarch == 'enable':85 if args.multiarch == 'enable':
583 multiarch = 'enabled'86 multiarch = 'enabled'
58487 self.containers_config.update_container_multiarch_support(args.id, multiarch)
585 current_multiarch = get_container_multiarch_support(args.id)88
586 if current_multiarch == multiarch:89 container = LibertineContainer(args.id)
587 print("i386 multiarch support is already %s" % multiarch)90 self.containers_config.update_container_install_status(args.id, "installing")
588 sys.exit(1)91 if not container.create_libertine_container(password, args.multiarch, args.verbosity):
58992 self.containers_config.delete_container(args.id)
590 if container.configure_command('multiarch', args.multiarch) is not 0:93 sys.exit(1)
591 sys.exit(1)94 self.containers_config.update_container_install_status(args.id, "ready")
59295
593 update_container_multiarch_support(args.id, multiarch)96 libertine.utils.refresh_libertine_scope()
59497
595 elif args.add_archive:98 def destroy_container_by_id(self, id):
596 if archive_exists(args.id, args.add_archive):99 container = LibertineContainer(id)
597 print("%s already added in container." % args.add_archive)100
598 sys.exit(1)101 self.containers_config.update_container_install_status(id, "removing")
599102 container.destroy_libertine_container()
600 add_container_archive(args.id, args.add_archive)103 self.containers_config.update_container_install_status(id, "removed")
601 update_archive_install_status(args.id, args.add_archive, 'installing')104 self.containers_config.delete_container(id)
602 if container.configure_command('add-archive', args.add_archive) is not 0:105
603 delete_container_archive(args.id, args.add_archive)106 def destroy(self, args):
604 sys.exit(1)107 args.id = self.containers_config.check_container_id(args.id)
605108
606 update_archive_install_status(args.id, args.add_archive, 'installed')109 self.destroy_container_by_id(args.id)
607110
608 elif args.delete_archive:111 libertine.utils.refresh_libertine_scope()
609 if not archive_exists(args.id, args.delete_archive):112
610 print("%s is not added in container." % args.delete_archive)113 def install_package(self, args):
611 sys.exit(1)114 container_id = self.containers_config.check_container_id(args.id)
612115
613 if not delete_archive_by_name(args.id, args.delete_archive):116 is_debian_package = args.package.endswith('.deb')
614 sys.exit(1)117
615118 if is_debian_package:
616119 if os.path.exists(args.package):
617def merge(args):120 package = DebPackage(args.package).pkgname
618 merge_container_config_files(args.file)121 else:
619122 print("%s does not exist." % args.package)
620123 sys.exit(1)
621def fix_integrity(args):124 else:
622 for container in read_container_config_file()['containerList']:125 package = args.package
623 if container['installStatus'] != 'ready':126
624 destroy_container_by_id(container['id'])127 if self.containers_config.package_exists(container_id, package):
625 continue128 if not is_debian_package:
626 LibertineContainer(container['id']).exec_command('dpkg --configure -a')129 print("Package \'%s\' is already installed." % package)
627130 sys.exit(1)
628 for package in container['installedApps']:131 else:
629 if package['appStatus'] != 'installed':132 self.containers_config.add_new_package(container_id, package)
630 remove_package_by_name(container['id'], package['packageName'])133
631 if 'extraArchives' in container:134 container = LibertineContainer(container_id)
632 for archive in container['extraArchives']:135
633 if archive['archiveStatus'] != 'installed':136 self.containers_config.update_package_install_status(container_id, package, "installing")
634 delete_archive_by_name(container['id'], archive['archiveName'])137 if not container.install_package(args.package, args.verbosity, args.readline):
635138 self.containers_config.delete_package(container_id, package)
636139 sys.exit(1)
637def set_default(args):140
638 if args.clear:141 self.containers_config.update_package_install_status(container_id, package, "installed")
639 container_list = read_container_config_file()142
640 container_list.pop('defaultContainer', None)143 libertine.utils.refresh_libertine_scope()
641 write_container_config_file(container_list)144
642 sys.exit(0)145 def remove_package_by_name(self, container_id, package_name, verbosity=1, readline=False):
643146 fallback_status = self.containers_config.get_package_install_status(container_id, package_name)
644 if not libertine.utils.container_exists(args.id):147 self.containers_config.update_package_install_status(container_id, package_name, "removing")
645 print("Container id \'%s\' does not exist." % args.id, file=sys.stderr)148
646 sys.exit(1)149 container = LibertineContainer(container_id)
647150 if not container.remove_package(package_name, verbosity, readline) and fallback_status == 'installed':
648 container_list = read_container_config_file()151 self.containers_config.update_package_install_status(container_id, package_name, fallback_status)
649 container_list['defaultContainer'] = args.id152 return False
650 write_container_config_file(container_list)153
154 self.containers_config.update_package_install_status(container_id, package_name, "removed")
155 self.containers_config.delete_package(container_id, package_name)
156
157 return True
158
159 def remove_package(self, args):
160 container_id = self.containers_config.check_container_id(args.id)
161
162 if self.containers_config.get_package_install_status(container_id, args.package) != 'installed':
163 print("Package \'%s\' is not installed." % args.package)
164 sys.exit(1)
165
166 if not self.remove_package_by_name(container_id, args.package, args.verbosity, args.readline):
167 sys.exit(1)
168
169 libertine.utils.refresh_libertine_scope()
170
171 def search_cache(self, args):
172 container_id = self.containers_config.check_container_id(args.id)
173
174 container = LibertineContainer(container_id)
175 if container.search_package_cache(args.search_string) is not 0:
176 sys.exit(1)
177
178 def update(self, args):
179 container_id = self.containers_config.check_container_id(args.id)
180
181 container = LibertineContainer(container_id)
182
183 self.containers_config.update_container_install_status(container_id, "updating")
184 if container.update_libertine_container(args.verbosity) is not 0:
185 self.containers_config.update_container_install_status(container_id, "ready")
186 sys.exit(1)
187
188 self.containers_config.update_container_install_status(container_id, "ready")
189
190 def list(self, args):
191 containers = libertine.utils.Libertine.list_containers()
192 for container in containers:
193 print("%s" % container)
194
195 def list_apps(self, args):
196 container_id = self.containers_config.check_container_id(args.id)
197
198 container = LibertineContainer(container_id)
199 print(container.list_app_launchers(use_json=args.json))
200
201 def exec(self, args):
202 container_id = self.containers_config.check_container_id(args.id)
203
204 container = LibertineContainer(container_id)
205
206 if not container.exec_command(args.command):
207 sys.exit(1)
208
209 def delete_archive_by_name(self, container_id, archive_name):
210 self.containers_config.update_archive_install_status(container_id, archive_name, 'removing')
211 if LibertineContainer(container_id).configure_command('delete-archive', archive_name) is not 0:
212 return False
213 self.containers_config.delete_container_archive(container_id, archive_name)
214 return True
215
216 def configure(self, args):
217 container_id = self.containers_config.check_container_id(args.id)
218
219 container = LibertineContainer(container_id)
220
221 if args.multiarch and self.host_info.get_host_architecture() == 'amd64':
222 multiarch = 'disabled'
223 if args.multiarch == 'enable':
224 multiarch = 'enabled'
225
226 current_multiarch = self.containers_config.get_container_multiarch_support(container_id)
227 if current_multiarch == multiarch:
228 print("i386 multiarch support is already %s" % multiarch)
229 sys.exit(1)
230
231 if container.configure_command('multiarch', args.multiarch) is not 0:
232 sys.exit(1)
233
234 self.containers_config.update_container_multiarch_support(container_id, multiarch)
235
236 elif args.add_archive:
237 if self.containers_config.archive_exists(container_id, args.add_archive):
238 print("%s already added in container." % args.add_archive)
239 sys.exit(1)
240
241 self.containers_config.add_container_archive(container_id, args.add_archive)
242 self.containers_config.update_archive_install_status(container_id, args.add_archive, 'installing')
243 if container.configure_command('add-archive', args.add_archive) is not 0:
244 self.containers_config.delete_container_archive(container_id, args.add_archive)
245 sys.exit(1)
246
247 self.containers_config.update_archive_install_status(container_id, args.add_archive, 'installed')
248
249 elif args.delete_archive:
250 if not self.containers_config.archive_exists(container_id, args.delete_archive):
251 print("%s is not added in container." % args.delete_archive)
252 sys.exit(1)
253
254 if not self.delete_archive_by_name(container_id, args.delete_archive):
255 sys.exit(1)
256
257 def merge(self, args):
258 self.containers_config.merge_container_config_files(args.file)
259
260 def fix_integrity(self, args):
261 for container in self.containers_config.container_list['containerList']:
262 if 'installStatus' not in container or container['installStatus'] != 'ready':
263 self.destroy_container_by_id(container['id'])
264 continue
265 LibertineContainer(container['id']).exec_command('dpkg --configure -a')
266
267 for package in container['installedApps']:
268 if package['appStatus'] != 'installed':
269 self.remove_package_by_name(container['id'], package['packageName'])
270
271 if 'extraArchives' in container:
272 for archive in container['extraArchives']:
273 if archive['archiveStatus'] != 'installed':
274 self.delete_archive_by_name(container['id'], archive['archiveName'])
275
276 def set_default(self, args):
277 if args.clear:
278 self.containers_config.clear_default_container_id(True)
279 sys.exit(0)
280
281 container_id = self.containers_config.check_container_id(args.id)
282
283 self.containers_config.set_default_container_id(container_id, True)
651284
652285
653if __name__ == '__main__':286if __name__ == '__main__':
@@ -657,6 +290,8 @@
657 print("Please do not run %s using sudo" % parser.prog)290 print("Please do not run %s using sudo" % parser.prog)
658 sys.exit(1)291 sys.exit(1)
659292
293 container_manager = LibertineContainerManager()
294
660 parser.add_argument('-q', '--quiet',295 parser.add_argument('-q', '--quiet',
661 action='store_const', dest='verbosity', const=0,296 action='store_const', dest='verbosity', const=0,
662 help=('do not print status updates on stdout'))297 help=('do not print status updates on stdout'))
@@ -696,7 +331,7 @@
696 '--password',331 '--password',
697 help=("Pass in the user's password when creating an LXC container. This "332 help=("Pass in the user's password when creating an LXC container. This "
698 "is intended for testing only and is very insecure."))333 "is intended for testing only and is very insecure."))
699 parser_create.set_defaults(func=create)334 parser_create.set_defaults(func=container_manager.create)
700335
701 # Handle the destroy command and its options336 # Handle the destroy command and its options
702 parser_destroy = subparsers.add_parser(337 parser_destroy = subparsers.add_parser(
@@ -705,7 +340,7 @@
705 parser_destroy.add_argument(340 parser_destroy.add_argument(
706 '-i', '--id',341 '-i', '--id',
707 help=("Container identifier. Default container is used if omitted."))342 help=("Container identifier. Default container is used if omitted."))
708 parser_destroy.set_defaults(func=destroy)343 parser_destroy.set_defaults(func=container_manager.destroy)
709344
710 # Handle the install-package command and its options345 # Handle the install-package command and its options
711 parser_install = subparsers.add_parser(346 parser_install = subparsers.add_parser(
@@ -721,7 +356,7 @@
721 parser_install.add_argument(356 parser_install.add_argument(
722 '-r', '--readline', action='store_true',357 '-r', '--readline', action='store_true',
723 help=("Readline mode. Use text-based frontend during debconf interactions."))358 help=("Readline mode. Use text-based frontend during debconf interactions."))
724 parser_install.set_defaults(func=install_package)359 parser_install.set_defaults(func=container_manager.install_package)
725360
726 # Handle the remove-package command and its options361 # Handle the remove-package command and its options
727 parser_remove = subparsers.add_parser(362 parser_remove = subparsers.add_parser(
@@ -737,7 +372,7 @@
737 parser_remove.add_argument(372 parser_remove.add_argument(
738 '-r', '--readline', action='store_true',373 '-r', '--readline', action='store_true',
739 help=("Readline mode. Use text-based frontend during debconf interactions."))374 help=("Readline mode. Use text-based frontend during debconf interactions."))
740 parser_remove.set_defaults(func=remove_package)375 parser_remove.set_defaults(func=container_manager.remove_package)
741376
742 # Handle the search-cache command and its options377 # Handle the search-cache command and its options
743 parser_search = subparsers.add_parser(378 parser_search = subparsers.add_parser(
@@ -750,7 +385,7 @@
750 parser_search.add_argument(385 parser_search.add_argument(
751 '-i', '--id',386 '-i', '--id',
752 help=("Container identifier. Default container is used if omitted."))387 help=("Container identifier. Default container is used if omitted."))
753 parser_search.set_defaults(func=search_cache)388 parser_search.set_defaults(func=container_manager.search_cache)
754389
755 # Handle the update command and its options390 # Handle the update command and its options
756 parser_update = subparsers.add_parser(391 parser_update = subparsers.add_parser(
@@ -759,13 +394,13 @@
759 parser_update.add_argument(394 parser_update.add_argument(
760 '-i', '--id',395 '-i', '--id',
761 help=("Container identifier. Default container is used if omitted."))396 help=("Container identifier. Default container is used if omitted."))
762 parser_update.set_defaults(func=update)397 parser_update.set_defaults(func=container_manager.update)
763398
764 # Handle the list command399 # Handle the list command
765 parser_list = subparsers.add_parser(400 parser_list = subparsers.add_parser(
766 "list",401 "list",
767 help=("List all Libertine containers."))402 help=("List all Libertine containers."))
768 parser_list.set_defaults(func=list)403 parser_list.set_defaults(func=container_manager.list)
769404
770 # Handle the list-apps command and its options405 # Handle the list-apps command and its options
771 parser_list_apps = subparsers.add_parser(406 parser_list_apps = subparsers.add_parser(
@@ -778,7 +413,7 @@
778 '-j', '--json',413 '-j', '--json',
779 action='store_true',414 action='store_true',
780 help=("use JSON output format."))415 help=("use JSON output format."))
781 parser_list_apps.set_defaults(func=list_apps)416 parser_list_apps.set_defaults(func=container_manager.list_apps)
782417
783 # Handle the execute command and it's options418 # Handle the execute command and it's options
784 parser_exec = subparsers.add_parser(419 parser_exec = subparsers.add_parser(
@@ -791,7 +426,7 @@
791 parser_exec.add_argument(426 parser_exec.add_argument(
792 '-c', '--command',427 '-c', '--command',
793 help=("The command to run in the specified container."))428 help=("The command to run in the specified container."))
794 parser_exec.set_defaults(func=exec)429 parser_exec.set_defaults(func=container_manager.exec)
795430
796 # Handle the configure command and it's options431 # Handle the configure command and it's options
797 parser_configure = subparsers.add_parser(432 parser_configure = subparsers.add_parser(
@@ -816,7 +451,7 @@
816 metavar='Archive name',451 metavar='Archive name',
817 help=("Deletes an existing archive (PPA) in the specified Libertine container. "452 help=("Deletes an existing archive (PPA) in the specified Libertine container. "
818 "Needs to be in the form of \"ppa:user/ppa-name\"."))453 "Needs to be in the form of \"ppa:user/ppa-name\"."))
819 parser_configure.set_defaults(func=configure)454 parser_configure.set_defaults(func=container_manager.configure)
820455
821 # Handle merging another ContainersConfig.json file into the main ContainersConfig.json file456 # Handle merging another ContainersConfig.json file into the main ContainersConfig.json file
822 parser_merge = subparsers.add_parser(457 parser_merge = subparsers.add_parser(
@@ -825,13 +460,13 @@
825 parser_merge.add_argument(460 parser_merge.add_argument(
826 '-f', '--file',461 '-f', '--file',
827 required=True)462 required=True)
828 parser_merge.set_defaults(func=merge)463 parser_merge.set_defaults(func=container_manager.merge)
829464
830 # Indiscriminately destroy containers, packages, and archives which are not fully installed465 # Indiscriminately destroy containers, packages, and archives which are not fully installed
831 parser_integrity = subparsers.add_parser(466 parser_integrity = subparsers.add_parser(
832 'fix-integrity',467 'fix-integrity',
833 add_help=False)468 add_help=False)
834 parser_integrity.set_defaults(func=fix_integrity)469 parser_integrity.set_defaults(func=container_manager.fix_integrity)
835470
836 # Set the default container in ContainersConfig471 # Set the default container in ContainersConfig
837 parser_default = subparsers.add_parser(472 parser_default = subparsers.add_parser(
@@ -844,7 +479,7 @@
844 parser_default.add_argument(479 parser_default.add_argument(
845 '-c', '--clear', action='store_true',480 '-c', '--clear', action='store_true',
846 help=("Clear the default container."))481 help=("Clear the default container."))
847 parser_default.set_defaults(func=set_default)482 parser_default.set_defaults(func=container_manager.set_default)
848483
849 # Actually parse the args484 # Actually parse the args
850 args = parser.parse_args()485 args = parser.parse_args()
851486
=== modified file 'tools/libertine-launch'
--- tools/libertine-launch 2016-05-10 20:17:44 +0000
+++ tools/libertine-launch 2016-07-07 20:14:07 +0000
@@ -18,21 +18,24 @@
1818
19import argparse19import argparse
20import os20import os
21import random
22import string
21import libertine.utils23import libertine.utils
22import psutil24import psutil
23import shlex25import shlex
24import time26import time
27
25from libertine import LibertineContainer28from libertine import LibertineContainer
2629
2730
28def get_session_socket_path(session_socket_name):31def get_session_socket_path(session_socket_name):
29 unique_id = os.environ['DISPLAY'].strip(':')32 unique_id = ''.join(random.choice(string.ascii_lowercase + string.digits) for i in range(8))
3033
31 if not os.path.exists(libertine.utils.get_libertine_runtime_dir()):34 if not os.path.exists(libertine.utils.get_libertine_runtime_dir()):
32 os.makedirs(libertine.utils.get_libertine_runtime_dir())35 os.makedirs(libertine.utils.get_libertine_runtime_dir())
3336
34 session_socket_path = (37 session_socket_path = (
35 os.path.join(libertine.utils.get_libertine_runtime_dir(), session_socket_name + unique_id))38 os.path.join(libertine.utils.get_libertine_runtime_dir(), session_socket_name + '-' + unique_id))
3639
37 return session_socket_path40 return session_socket_path
3841
@@ -69,8 +72,8 @@
6972
70 while not os.path.exists(session_socket_path):73 while not os.path.exists(session_socket_path):
71 if retries >= 10:74 if retries >= 10:
72 raise RuntimeError("Timeout waiting for Libertine Dbus session bridge socket") 75 raise RuntimeError("Timeout waiting for Libertine Dbus session bridge socket")
73 76
74 print("Libertine Dbus session bridge socket is not ready. Waiting...")77 print("Libertine Dbus session bridge socket is not ready. Waiting...")
75 retries += 178 retries += 1
76 time.sleep(.5)79 time.sleep(.5)
@@ -84,9 +87,6 @@
84 help='exec line')87 help='exec line')
85 args = arg_parser.parse_args()88 args = arg_parser.parse_args()
8689
87 if not libertine.utils.container_exists(args.container_id):
88 raise RuntimeError("Container ID %s does not exist." % args.container_id)
89
90 # remove problematic environment variables90 # remove problematic environment variables
91 for e in ['QT_QPA_PLATFORM', 'LD_LIBRARY_PATH', 'FAKECHROOT_BASE', 'FAKECHROOT_CMD_SUBST']:91 for e in ['QT_QPA_PLATFORM', 'LD_LIBRARY_PATH', 'FAKECHROOT_BASE', 'FAKECHROOT_CMD_SUBST']:
92 if e in os.environ:92 if e in os.environ:
@@ -104,7 +104,7 @@
104 # should detect the maliit socket, but dont know if its around or not here.104 # should detect the maliit socket, but dont know if its around or not here.
105 detect_session_bridge_socket(dbus_socket_path)105 detect_session_bridge_socket(dbus_socket_path)
106106
107 container = LibertineContainer(args.container_id) 107 container = LibertineContainer(args.container_id)
108108
109 try:109 try:
110 container.launch_application(args.app_exec_line)110 container.launch_application(args.app_exec_line)
111111
=== modified file 'tools/libertine-session-bridge'
--- tools/libertine-session-bridge 2016-05-19 20:00:22 +0000
+++ tools/libertine-session-bridge 2016-07-07 20:14:07 +0000
@@ -170,6 +170,7 @@
170 except:170 except:
171 container_session_sock.close()171 container_session_sock.close()
172 container_session_sock = None172 container_session_sock = None
173 os.remove(session_socket_path)
173 raise174 raise
174 else:175 else:
175 host_session_socket_path_map.update({container_session_sock:host_session_path})176 host_session_socket_path_map.update({container_session_sock:host_session_path})

Subscribers

People subscribed via source and target branches