Merge lp:~larryprice/libertine/bind-mount-gui into lp:libertine

Proposed by Larry Price
Status: Merged
Approved by: Larry Price
Approved revision: 399
Merged at revision: 411
Proposed branch: lp:~larryprice/libertine/bind-mount-gui
Merge into: lp:libertine
Diff against target: 698 lines (+387/-18)
18 files modified
common/CMakeLists.txt (+1/-0)
common/ContainerArchivesList.cpp (+1/-0)
common/ContainerArchivesList.h (+3/-4)
common/ContainerBindMountsList.cpp (+87/-0)
common/ContainerBindMountsList.h (+76/-0)
common/ContainerConfigList.cpp (+8/-1)
common/ContainerConfigList.h (+10/-8)
common/ContainersConfig.cpp (+25/-1)
common/ContainersConfig.h (+14/-0)
debian/control (+1/-0)
libertine/CMakeLists.txt (+1/-3)
libertine/libertine.cpp (+3/-0)
libertine/libertine.h (+2/-0)
qml/common/AddBindMountDialog.qml (+27/-0)
qml/common/ExtraBindMountsView.qml (+110/-0)
qml/common/ManageContainer.qml (+9/-0)
tests/unit/ContainersConfigTests.cpp (+8/-0)
tools/libertine-container-manager (+1/-1)
To merge this branch: bzr merge lp:~larryprice/libertine/bind-mount-gui
Reviewer Review Type Date Requested Status
Libertine CI Bot continuous-integration Approve
Christopher Townsend Approve
Review via email: mp+317546@code.launchpad.net

Commit message

Implement GUI for adding and removing bind-mounts in containers.

Description of the change

Implement GUI for adding and removing bind-mounts to containers.

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

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

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

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

As mentioned on irc, the FileDialog pops up as a very small horizontal line and I happened to resize it by chance. If there is a way to try to set a default size for the dialog, that would be great.

Also, a couple of code style nitpicks inline.

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

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

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

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

Ok, +1.

I will note that there isn't any way to protect against the weird horizontal line FileDialog I saw, so we'll leave it as is and hope I'm the outlier.

review: Approve
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'common/CMakeLists.txt'
2--- common/CMakeLists.txt 2017-02-08 14:09:03 +0000
3+++ common/CMakeLists.txt 2017-02-22 20:19:40 +0000
4@@ -1,6 +1,7 @@
5 add_library(${LIBERTINE_COMMON}
6 ContainerAppsList.cpp
7 ContainerArchivesList.cpp
8+ ContainerBindMountsList.cpp
9 ContainersConfig.cpp
10 ContainerConfigList.cpp
11 ContainerManager.cpp
12
13=== modified file 'common/ContainerArchivesList.cpp'
14--- common/ContainerArchivesList.cpp 2017-02-08 14:57:34 +0000
15+++ common/ContainerArchivesList.cpp 2017-02-22 20:19:40 +0000
16@@ -20,6 +20,7 @@
17
18 #include "common/ContainerConfigList.h"
19
20+
21 ContainerArchivesList::
22 ContainerArchivesList(ContainerConfigList* container_config_list,
23 QObject* parent)
24
25=== modified file 'common/ContainerArchivesList.h'
26--- common/ContainerArchivesList.h 2017-02-08 13:10:10 +0000
27+++ common/ContainerArchivesList.h 2017-02-22 20:19:40 +0000
28@@ -18,14 +18,13 @@
29 */
30 #pragma once
31
32+#include "common/ContainersConfig.h"
33 #include <QtCore/QAbstractListModel>
34 #include <QtCore/QList>
35 #include <QtCore/QObject>
36 #include <QtCore/QString>
37-#include "common/ContainersConfig.h"
38-
39-
40-class ContainerArchives;
41+
42+
43 class ContainerConfigList;
44
45 class ContainerArchivesList
46
47=== added file 'common/ContainerBindMountsList.cpp'
48--- common/ContainerBindMountsList.cpp 1970-01-01 00:00:00 +0000
49+++ common/ContainerBindMountsList.cpp 2017-02-22 20:19:40 +0000
50@@ -0,0 +1,87 @@
51+/**
52+ * @file ContainerBindMountsList.cpp
53+ * @brief Libertine Manager list of all mapped directories
54+ */
55+/*
56+ * Copyright 2017 Canonical Ltd
57+ *
58+ * Libertine is free software: you can redistribute it and/or modify it under
59+ * the terms of the GNU General Public License, version 3, as published by the
60+ * Free Software Foundation.
61+ *
62+ * Libertine is distributed in the hope that it will be useful, but WITHOUT ANY
63+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
64+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
65+ *
66+ * You should have received a copy of the GNU General Public License
67+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
68+ */
69+#include "common/ContainerBindMountsList.h"
70+
71+#include "common/ContainerConfigList.h"
72+
73+
74+ContainerBindMountsList::
75+ContainerBindMountsList(ContainerConfigList* container_config_list,
76+ QObject* parent)
77+: QAbstractListModel(parent)
78+, container_config_list_(container_config_list)
79+{ }
80+
81+
82+void ContainerBindMountsList::
83+setContainerBindMounts(QString const& container_id)
84+{
85+ mounts_ = container_config_list_->getBindMountsForContainer(container_id);
86+
87+ beginResetModel();
88+ endResetModel();
89+}
90+
91+
92+bool ContainerBindMountsList::
93+empty() const noexcept
94+{ return mounts_.empty(); }
95+
96+
97+ContainerBindMountsList::size_type ContainerBindMountsList::
98+size() const noexcept
99+{ return mounts_.count(); }
100+
101+
102+int ContainerBindMountsList::
103+rowCount(QModelIndex const&) const
104+{
105+ return this->size();
106+}
107+
108+
109+QHash<int, QByteArray> ContainerBindMountsList::
110+roleNames() const
111+{
112+ QHash<int, QByteArray> roles;
113+ roles[static_cast<int>(DataRole::BindMountPath)] = "path";
114+
115+ return roles;
116+}
117+
118+
119+QVariant ContainerBindMountsList::
120+data(QModelIndex const& index, int role) const
121+{
122+ QVariant result;
123+
124+ if (index.isValid() && index.row() <= mounts_.count())
125+ {
126+ switch (static_cast<DataRole>(role))
127+ {
128+ case DataRole::BindMountPath:
129+ result = mounts_[index.row()].path;
130+ break;
131+ case DataRole::Error:
132+ break;
133+ }
134+ }
135+
136+ return result;
137+}
138
139=== added file 'common/ContainerBindMountsList.h'
140--- common/ContainerBindMountsList.h 1970-01-01 00:00:00 +0000
141+++ common/ContainerBindMountsList.h 2017-02-22 20:19:40 +0000
142@@ -0,0 +1,76 @@
143+/**
144+ * @file ContainerBindMountsList.h
145+ * @brief Libertine Manager list of extra container archives (PPAs)
146+ */
147+/*
148+ * Copyright 2017 Canonical Ltd
149+ *
150+ * Libertine is free software: you can redistribute it and/or modify it under
151+ * the terms of the GNU General Public License, version 3, as published by the
152+ * Free Software Foundation.
153+ *
154+ * Libertine is distributed in the hope that it will be useful, but WITHOUT ANY
155+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
156+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
157+ *
158+ * You should have received a copy of the GNU General Public License
159+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
160+ */
161+#pragma once
162+
163+#include "common/ContainersConfig.h"
164+#include <QtCore/QAbstractListModel>
165+#include <QtCore/QList>
166+#include <QtCore/QObject>
167+#include <QtCore/QString>
168+
169+
170+class ContainerConfigList;
171+
172+class ContainerBindMountsList
173+: public QAbstractListModel
174+{
175+ Q_OBJECT
176+
177+public:
178+ using BindMountsList = QList<ContainersConfig::Container::BindMount>;
179+ using iterator = BindMountsList::iterator;
180+ using size_type = BindMountsList::size_type;
181+
182+ enum class DataRole
183+ : int
184+ {
185+ BindMountPath = Qt::UserRole + 1,
186+ Error
187+ };
188+
189+public:
190+ explicit
191+ ContainerBindMountsList(ContainerConfigList* container_config_list,
192+ QObject* parent = nullptr);
193+
194+ virtual
195+ ~ContainerBindMountsList() = default;
196+
197+ Q_INVOKABLE void
198+ setContainerBindMounts(QString const& container_id);
199+
200+ Q_INVOKABLE bool
201+ empty() const noexcept;
202+
203+ size_type
204+ size() const noexcept;
205+
206+ int
207+ rowCount(QModelIndex const& parent = QModelIndex()) const;
208+
209+ QHash<int, QByteArray>
210+ roleNames() const;
211+
212+ QVariant
213+ data(QModelIndex const& index, int role = Qt::DisplayRole) const;
214+
215+private:
216+ ContainerConfigList* container_config_list_;
217+ BindMountsList mounts_;
218+};
219
220=== modified file 'common/ContainerConfigList.cpp'
221--- common/ContainerConfigList.cpp 2017-02-08 15:08:24 +0000
222+++ common/ContainerConfigList.cpp 2017-02-22 20:19:40 +0000
223@@ -34,9 +34,9 @@
224 #include <QtCore/QStandardPaths>
225 #include <QtCore/QString>
226 #include <QtCore/QSysInfo>
227-
228 #include <sys/file.h>
229
230+
231 namespace
232 {
233 static constexpr auto POLICY_INSTALLED_VERSION_LINE = 1;
234@@ -235,6 +235,13 @@
235 }
236
237
238+QList<ContainersConfig::Container::BindMount> ContainerConfigList::
239+getBindMountsForContainer(QString const& container_id)
240+{
241+ return find_container_by_id(containers_config_->containers, container_id).mounts;
242+}
243+
244+
245 QString ContainerConfigList::
246 getContainerType(QString const& container_id)
247 {
248
249=== modified file 'common/ContainerConfigList.h'
250--- common/ContainerConfigList.h 2017-02-13 20:57:03 +0000
251+++ common/ContainerConfigList.h 2017-02-22 20:19:40 +0000
252@@ -18,15 +18,15 @@
253 */
254 #pragma once
255
256+
257+#include "common/ContainersConfig.h"
258+#include <memory>
259 #include <QtCore/QAbstractListModel>
260 #include <QtCore/QJsonObject>
261 #include <QtCore/QList>
262-#include <memory>
263-#include "common/ContainersConfig.h"
264+
265
266 class ContainerApps;
267-class ContainerArchives;
268-class ContainerConfig;
269 class LibertineConfig;
270
271
272@@ -44,9 +44,7 @@
273 NOTIFY defaultContainerChanged)
274
275 public:
276- using ConfigList = QList<ContainerConfig*>;
277- using iterator = ConfigList::iterator;
278- using size_type = ConfigList::size_type;
279+ using size_type = QList<ContainersConfig::Container>::size_type;
280
281 static const QString Json_container_list;
282 static const QString Json_default_container;
283@@ -74,12 +72,14 @@
284 /**
285 * Constructs a container config list from a container config.
286 */
287+ explicit
288 ContainerConfigList(LibertineConfig const* config,
289 QObject* parent = nullptr);
290
291 /**
292 * Constructs a container config list from a raw json string
293 */
294+ explicit
295 ContainerConfigList(QJsonObject const& json_object,
296 QObject* parent = nullptr);
297
298@@ -127,6 +127,9 @@
299 QList<ContainersConfig::Container::Archive>
300 getArchivesForContainer(QString const& container_id);
301
302+ QList<ContainersConfig::Container::BindMount>
303+ getBindMountsForContainer(QString const& container_id);
304+
305 Q_INVOKABLE QString
306 getContainerType(QString const& container_id);
307
308@@ -228,7 +231,6 @@
309
310 private:
311 LibertineConfig const* config_;
312- ConfigList configs_;
313 QString default_container_id_;
314 std::unique_ptr<ContainersConfig> containers_config_;
315 };
316
317=== modified file 'common/ContainersConfig.cpp'
318--- common/ContainersConfig.cpp 2017-02-13 22:18:18 +0000
319+++ common/ContainersConfig.cpp 2017-02-22 20:19:40 +0000
320@@ -12,7 +12,6 @@
321 * You should have received a copy of the GNU General Public License
322 * along with this program. If not, see <http://www.gnu.org/licenses/>.
323 */
324-
325 #include "ContainersConfig.h"
326
327 #include <QJsonArray>
328@@ -63,6 +62,19 @@
329 }
330
331
332+ContainersConfig::Container::BindMount::
333+BindMount(QString const& json)
334+: path(json)
335+{ }
336+
337+
338+QString ContainersConfig::Container::BindMount::
339+dump() const
340+{
341+ return path;
342+}
343+
344+
345 ContainersConfig::Container::InstalledApp::
346 InstalledApp(QJsonObject const& json)
347 : status_(try_get_string(json, "appStatus"))
348@@ -110,6 +122,11 @@
349 {
350 installed_apps.append(InstalledApp(app.toObject()));
351 }
352+
353+ for (auto const& mount: json["bindMounts"].toArray())
354+ {
355+ mounts.append(BindMount(mount.toString()));
356+ }
357 }
358
359
360@@ -138,6 +155,13 @@
361 }
362 object["installedApps"] = installed_apps_list;
363
364+ QJsonArray mounts_list;
365+ for (auto const& mount: mounts)
366+ {
367+ mounts_list.append(mount.dump());
368+ }
369+ object["bindMounts"] = mounts_list;
370+
371 return object;
372 }
373
374
375=== modified file 'common/ContainersConfig.h'
376--- common/ContainersConfig.h 2017-02-13 22:18:18 +0000
377+++ common/ContainersConfig.h 2017-02-22 20:19:40 +0000
378@@ -73,6 +73,19 @@
379 QString status;
380 };
381
382+
383+ class BindMount
384+ {
385+ public:
386+ explicit BindMount(QString const& json);
387+ virtual ~BindMount() = default;
388+
389+ QString dump() const;
390+
391+ public:
392+ QString path;
393+ };
394+
395 private:
396 QString status_; // untranslated
397
398@@ -84,6 +97,7 @@
399 QString type;
400 QString multiarch;
401 QList<Archive> archives;
402+ QList<BindMount> mounts;
403 QList<InstalledApp> installed_apps;
404 };
405
406
407=== modified file 'debian/control'
408--- debian/control 2017-02-16 14:05:23 +0000
409+++ debian/control 2017-02-22 20:19:40 +0000
410@@ -73,6 +73,7 @@
411 Package: libertine-qt-common
412 Architecture: any
413 Depends: qml-module-qtquick2,
414+ qml-module-qtquick-dialogs,
415 qtdeclarative5-ubuntu-ui-toolkit-plugin,
416 ${misc:Depends},
417 ${shlibs:Depends}
418
419=== modified file 'libertine/CMakeLists.txt'
420--- libertine/CMakeLists.txt 2016-10-07 21:04:06 +0000
421+++ libertine/CMakeLists.txt 2017-02-22 20:19:40 +0000
422@@ -12,8 +12,6 @@
423 )
424
425 add_executable(${LIBERTINE_EXE_NAME} ${libertine_SRC})
426-target_link_libraries(${LIBERTINE_EXE_NAME} ${LIBERTINE_COMMON} ${LIBERTINE_CORE} Qt5::Core Qt5::Quick Qt5::Gui)
427-
428-install(DIRECTORY qml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${CMAKE_PROJECT_NAME})
429+target_link_libraries(${LIBERTINE_EXE_NAME} ${LIBERTINE_COMMON} Qt5::Core Qt5::Quick Qt5::Gui)
430
431 install(TARGETS ${LIBERTINE_EXE_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
432
433=== modified file 'libertine/libertine.cpp'
434--- libertine/libertine.cpp 2017-02-08 14:23:49 +0000
435+++ libertine/libertine.cpp 2017-02-22 20:19:40 +0000
436@@ -21,6 +21,7 @@
437 #include "common/ContainerManager.h"
438 #include "common/ContainerAppsList.h"
439 #include "common/ContainerArchivesList.h"
440+#include "common/ContainerBindMountsList.h"
441 #include "common/ContainerConfigList.h"
442 #include "common/LibertineConfig.h"
443 #include "common/PackageOperationDetails.h"
444@@ -114,6 +115,7 @@
445 containers_ = new ContainerConfigList(config_.data(), this);
446 container_apps_ = new ContainerAppsList(containers_, this);
447 container_archives_ = new ContainerArchivesList(containers_, this);
448+ container_bind_mounts_ = new ContainerBindMountsList(containers_, this);
449 package_operation_details_ = new PackageOperationDetails(this);
450
451 initialize_view();
452@@ -141,6 +143,7 @@
453 ctxt->setContextProperty("containerConfigList", containers_);
454 ctxt->setContextProperty("containerAppsList", container_apps_);
455 ctxt->setContextProperty("containerArchivesList", container_archives_);
456+ ctxt->setContextProperty("containerBindMountsList", container_bind_mounts_);
457 ctxt->setContextProperty("packageOperationDetails", package_operation_details_);
458
459 view_.setSource(QUrl::fromLocalFile(main_qml_source_file_));
460
461=== modified file 'libertine/libertine.h'
462--- libertine/libertine.h 2016-10-03 20:30:29 +0000
463+++ libertine/libertine.h 2017-02-22 20:19:40 +0000
464@@ -30,6 +30,7 @@
465 class LibertineConfig;
466 class ContainerAppsList;
467 class ContainerArchivesList;
468+class ContainerBindMountsList;
469 class PackageOperationDetails;
470
471
472@@ -57,6 +58,7 @@
473 ContainerConfigList* containers_;
474 ContainerAppsList* container_apps_;
475 ContainerArchivesList* container_archives_;
476+ ContainerBindMountsList* container_bind_mounts_;
477 PackageOperationDetails* package_operation_details_;
478 QQuickView view_;
479 };
480
481=== removed directory 'libertine/qml'
482=== added file 'qml/common/AddBindMountDialog.qml'
483--- qml/common/AddBindMountDialog.qml 1970-01-01 00:00:00 +0000
484+++ qml/common/AddBindMountDialog.qml 2017-02-22 20:19:40 +0000
485@@ -0,0 +1,27 @@
486+/*
487+ * Copyright 2017 Canonical Ltd
488+ *
489+ * Libertine is free software: you can redistribute it and/or modify it under
490+ * the terms of the GNU General Public License, version 3, as published by the
491+ * Free Software Foundation.
492+ *
493+ * Libertine is distributed in the hope that it will be useful, but WITHOUT ANY
494+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
495+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
496+ *
497+ * You should have received a copy of the GNU General Public License
498+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
499+ */
500+import QtQuick 2.4
501+import QtQuick.Dialogs 1.0
502+
503+FileDialog {
504+ id: addBindMountDialog
505+ title: "Choose directory to bind-mount"
506+ selectFolder: true
507+ onAccepted: {
508+ if (addBindMountDialog.fileUrl) {
509+ extraBindMountsView.addBindMount(addBindMountDialog.fileUrl.toString().replace("file:///", "/"))
510+ }
511+ }
512+}
513
514=== added file 'qml/common/ExtraBindMountsView.qml'
515--- qml/common/ExtraBindMountsView.qml 1970-01-01 00:00:00 +0000
516+++ qml/common/ExtraBindMountsView.qml 2017-02-22 20:19:40 +0000
517@@ -0,0 +1,110 @@
518+/*
519+ * Copyright 2017 Canonical Ltd
520+ *
521+ * Libertine is free software: you can redistribute it and/or modify it under
522+ * the terms of the GNU General Public License, version 3, as published by the
523+ * Free Software Foundation.
524+ *
525+ * Libertine is distributed in the hope that it will be useful, but WITHOUT ANY
526+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
527+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
528+ *
529+ * You should have received a copy of the GNU General Public License
530+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
531+ */
532+import Libertine 1.0
533+import QtQuick 2.4
534+import Ubuntu.Components 1.3
535+
536+Page {
537+ id: extraBindMountsView
538+ clip: true
539+ header: PageHeader {
540+ id: pageHeader
541+ title: i18n.tr("Mapped Directories")
542+ trailingActionBar.actions: [
543+ Action {
544+ iconName: "add"
545+ text: i18n.tr("add")
546+ description: i18n.tr("Add a new bind-mount")
547+ onTriggered: {
548+ var fileDialog = Qt.createComponent("AddBindMountDialog.qml").createObject(extraBindMountsView)
549+ fileDialog.open()
550+ }
551+ }
552+ ]
553+ }
554+ property string currentContainer: ""
555+
556+ signal error(string description, string details)
557+
558+ UbuntuListView {
559+ id: bindMountsListView
560+ anchors {
561+ topMargin: pageHeader.height
562+ fill: parent
563+ }
564+ model: containerBindMountsList
565+ visible: !containerBindMountsList.empty()
566+ delegate: ListItem {
567+ Label {
568+ anchors {
569+ verticalCenter: parent.verticalCenter
570+ left: parent.left
571+ leftMargin: units.gu(2)
572+ }
573+ text: path
574+ width: parent.width - units.gu(8)
575+ elide: Text.ElideMiddle
576+ }
577+ leadingActions: ListItemActions {
578+ actions: [
579+ Action {
580+ iconName: "delete"
581+ text: i18n.tr("remove")
582+ description: i18n.tr("Remove mapped directory")
583+ onTriggered: {
584+ deleteBindMount(path)
585+ }
586+ }
587+ ]
588+ }
589+ }
590+ }
591+
592+ Label {
593+ id: emptyLabel
594+ anchors.centerIn: parent
595+ visible: !bindMountsListView.visible
596+ wrapMode: Text.Wrap
597+ width: parent.width
598+ horizontalAlignment: Text.AlignHCenter
599+ text: i18n.tr("No custom bind-mounts have been added to this container.\n" +
600+ "Adding a directory here will allow you to modify its contents within this container.")
601+ }
602+
603+ function deleteBindMount(mount) {
604+ var worker = Qt.createComponent("ContainerManager.qml").createObject(mainView)
605+ worker.error.connect(packageOperationDetails.error)
606+ worker.configureContainer(currentContainer, containerConfigList.getContainerName(currentContainer), ["--bind-mount", "remove", "--mount-path", "\"" + mount + "\""])
607+ }
608+
609+ function addBindMount(mount) {
610+ var worker = Qt.createComponent("ContainerManager.qml").createObject(mainView)
611+ worker.error.connect(packageOperationDetails.error)
612+ worker.configureContainer(currentContainer, containerConfigList.getContainerName(currentContainer), ["--bind-mount", "add", "--mount-path", "\"" + mount + "\""])
613+ }
614+
615+ Component.onCompleted: {
616+ containerConfigList.configChanged.connect(reloadMounts)
617+ }
618+
619+ Component.onDestruction: {
620+ containerConfigList.configChanged.disconnect(reloadMounts)
621+ }
622+
623+ function reloadMounts() {
624+ containerBindMountsList.setContainerBindMounts(currentContainer)
625+ bindMountsListView.visible = !containerBindMountsList.empty()
626+ }
627+}
628
629=== modified file 'qml/common/ManageContainer.qml'
630--- qml/common/ManageContainer.qml 2017-02-06 16:35:18 +0000
631+++ qml/common/ManageContainer.qml 2017-02-22 20:19:40 +0000
632@@ -78,6 +78,15 @@
633 }
634 }
635
636+ ListItem.SingleValue {
637+ text: i18n.tr("Additional bind-mounts")
638+ progression: true
639+ onClicked: {
640+ containerBindMountsList.setContainerBindMounts(currentContainer)
641+ pageStack.addPageToNextColumn(manageView, Qt.resolvedUrl("ExtraBindMountsView.qml"), {currentContainer: currentContainer})
642+ }
643+ }
644+
645 ListItem.Standard {
646 control: Button {
647 id: updateButton
648
649=== modified file 'tests/unit/ContainersConfigTests.cpp'
650--- tests/unit/ContainersConfigTests.cpp 2017-02-13 22:18:18 +0000
651+++ tests/unit/ContainersConfigTests.cpp 2017-02-22 20:19:40 +0000
652@@ -48,6 +48,9 @@
653 "archiveName": "ppa:some/archive",
654 "archiveStatus": "installed"
655 }
656+ ],
657+ "bindMounts": [
658+ "/media/lrp/PEPPER"
659 ]
660 },
661 {
662@@ -107,6 +110,9 @@
663 ASSERT_EQ(config.containers[0].archives.size(), 1);
664 EXPECT_EQ(config.containers[0].archives[0].status, "installed");
665 EXPECT_EQ(config.containers[0].archives[0].name, "ppa:some/archive");
666+
667+ ASSERT_EQ(config.containers[0].mounts.size(), 1);
668+ EXPECT_EQ(config.containers[0].mounts[0].path, "/media/lrp/PEPPER");
669 }
670
671
672@@ -124,6 +130,7 @@
673 auto zesty = json["containerList"].toArray()[1].toObject();
674 zesty["installedApps"] = QJsonArray();
675 zesty["extraArchives"] = QJsonArray();
676+ zesty["bindMounts"] = QJsonArray();
677 json["containerList"] = QJsonArray{xenial, zesty};
678
679 EXPECT_EQ(json, actual);
680@@ -141,4 +148,5 @@
681 EXPECT_EQ(container.status, "unknown");
682 EXPECT_TRUE(container.archives.isEmpty());
683 EXPECT_TRUE(container.installed_apps.isEmpty());
684+ EXPECT_TRUE(container.mounts.isEmpty());
685 }
686
687=== modified file 'tools/libertine-container-manager'
688--- tools/libertine-container-manager 2017-02-14 20:26:49 +0000
689+++ tools/libertine-container-manager 2017-02-22 20:19:40 +0000
690@@ -307,7 +307,7 @@
691 libertine.utils.get_logger().error("Configure bind-mounts called without mount path. See configure --help for usage")
692 sys.exit(1)
693
694- mount_path = args.mount_path.rstrip('/')
695+ mount_path = args.mount_path.rstrip('/').strip('"')
696
697 # validate bind-mount
698 if not mount_path.startswith(os.environ['HOME']) and not mount_path.startswith('/media/%s' % os.environ['USER']):

Subscribers

People subscribed via source and target branches