Merge lp:~xavi-garcia-mena/keeper/command-line-client-plus-bugs into lp:keeper/devel
- command-line-client-plus-bugs
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Xavi Garcia |
Approved revision: | 128 |
Merged at revision: | 124 |
Proposed branch: | lp:~xavi-garcia-mena/keeper/command-line-client-plus-bugs |
Merge into: | lp:keeper/devel |
Diff against target: |
1578 lines (+1048/-93) 27 files modified
data/CMakeLists.txt (+6/-0) debian/keeper.install (+1/-0) include/client/client.h (+8/-0) src/cli/CMakeLists.txt (+4/-0) src/cli/command-line-client-view.cpp (+128/-0) src/cli/command-line-client-view.h (+57/-0) src/cli/command-line-client.cpp (+247/-0) src/cli/command-line-client.h (+53/-0) src/cli/command-line.cpp (+188/-0) src/cli/command-line.h (+52/-0) src/cli/main.cpp (+29/-46) src/client/CMakeLists.txt (+5/-0) src/client/client.cpp (+148/-35) src/helper/CMakeLists.txt (+15/-0) src/helper/folder-restore.sh.in (+23/-0) src/helper/restore-helper.cpp (+5/-0) src/qdbus-stubs/CMakeLists.txt (+21/-4) src/qdbus-stubs/dbus-types.h (+1/-2) src/qdbus-stubs/org.freedesktop.DBus.Properties.xml (+27/-0) src/service/keeper.cpp (+11/-0) src/service/main.cpp (+2/-1) src/service/task-manager.cpp (+8/-2) src/service/task-manager.h (+1/-0) src/storage-framework/storage_framework_client.cpp (+3/-3) tests/unit/helper/CMakeLists.txt (+1/-0) tests/unit/manifest/CMakeLists.txt (+1/-0) tests/unit/metadata-providers/CMakeLists.txt (+3/-0) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/keeper/command-line-client-plus-bugs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
unity-api-1-bot | continuous-integration | Approve | |
Charles Kerr (community) | Approve | ||
Review via email: mp+312257@code.launchpad.net |
Commit message
Changes to command line client and some bugs fixed.
Description of the change
Changes to command line client and some bugs fixed.
This branch changes the command line client to follow the design specs and to show the status of each active task.
The command line client has a separated class for the view, so changing HOW we show the results should be independent of the rest of the code.
It also fixed the following issues:
- Bug when getting downloader, some variables needed to be captured.
- Avoid setting current state for last task until manifest is stored.
- When task manager finishes all tasks we clear the backup choices cache. We do this to avoid repeating uuids in between backups. So if we start 2 backups the uuids now are different. They were equal previously and that created issues when obtaining the restore options, as they are identified by uuid.
What's missing:
* Command line library:
- We need to change the code style to follow the rest of the project's code.
- The library is oriented to the qml app, and only for backups, so some re-design will be necessary.
- We need to add the start restore functionality. Obtaining the restore choices is already done.
* Command line client:
- The output now is using special escape characters. We should investigate if there's something cleaner. (That would mean changes only in the view class)
- Add restore functionality
- Completely follow the specs. For example now the storage is unique and it only uses the option --storage to identify that we want to list the available options in the storage (restore options). To do this we need to change the storage framework client class in order to choose from different accounts and/or storages.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
- 123. By Xavi Garcia
-
conflict resolved
Xavi Garcia (xavi-garcia-mena) wrote : | # |
It also fixes the dependency issues and undefined symbols that the client library had.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:146
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:123
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 124. By Xavi Garcia
-
Added restore in command line client, added restore in backup registry with empty folder helper
- 125. By Xavi Garcia
-
Added folder-
restore. sh.in - 126. By Xavi Garcia
-
fixed debian packaging
- 127. By Xavi Garcia
-
Fix cppcheck test in zesty
Charles Kerr (charlesk) wrote : | # |
Some optional suggestions inline, no blockers. LGTM.
- 128. By Xavi Garcia
-
Suggested changes in review
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Thanks for the review, Charles!
I've changed the code following your suggestions.
I only kept the "return true" statement in those two methods as the intention is to add more flags and options in the future...
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:128
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Michi Henning (michihenning) wrote : | # |
Asking out of curiosity:
"When task manager finishes all tasks we clear the backup choices cache. We do this to avoid repeating uuids in between backups."
That sounded strange to me. I mean, what sort of UUID generator comes up with same UUID twice?
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Hi Michi,
We clear the cache of uuids because if we run a backup twice we don't repeat the same UUID.
If the cache is not empty we don't recalculate the UUIDs, we need that in between calls to list-sections and backup as we need the UUIDs to be the same after asking for the list of available sections to backup and the moment when we run that backup. (the backup is triggered passing a list of uuids)
But, if we don't clean the uuids when the backup finishes and the user triggers a second backup, the uuids are the same, which is a problem when trying to restore as we'll have 2 backups with the same uuid.
makes sense?
Preview Diff
1 | === modified file 'data/CMakeLists.txt' |
2 | --- data/CMakeLists.txt 2016-08-10 07:43:36 +0000 |
3 | +++ data/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
4 | @@ -6,6 +6,12 @@ |
5 | FOLDER_BACKUP_EXEC |
6 | ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-backup.sh |
7 | ) |
8 | + |
9 | +set( |
10 | + FOLDER_RESTORE_EXEC |
11 | + ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-restore.sh |
12 | +) |
13 | + |
14 | configure_file( |
15 | ${HELPER_REGISTRY_FILENAME}.in |
16 | ${HELPER_REGISTRY_FILENAME} |
17 | |
18 | === modified file 'debian/keeper.install' |
19 | --- debian/keeper.install 2016-08-10 07:43:36 +0000 |
20 | +++ debian/keeper.install 2016-12-16 09:34:32 +0000 |
21 | @@ -1,4 +1,5 @@ |
22 | /usr/lib/*/keeper/folder-backup.sh |
23 | +/usr/lib/*/keeper/folder-restore.sh |
24 | /usr/lib/*/keeper/keeper-service |
25 | /usr/lib/*/keeper/keeper-tar-create |
26 | /usr/lib/*/ubuntu-app-launch/backup-helper/exec-tool |
27 | |
28 | === modified file 'include/client/client.h' |
29 | --- include/client/client.h 2016-09-06 18:28:45 +0000 |
30 | +++ include/client/client.h 2016-12-16 09:34:32 +0000 |
31 | @@ -55,10 +55,15 @@ |
32 | Q_INVOKABLE void enableBackup(QString uuid, bool enabled); |
33 | Q_INVOKABLE void startBackup(); |
34 | |
35 | + Q_INVOKABLE void enableRestore(QString uuid, bool enabled); |
36 | + Q_INVOKABLE void startRestore(); |
37 | + |
38 | // C++ |
39 | public: |
40 | QMap<QString, QVariantMap> getBackupChoices() const; |
41 | + QMap<QString, QVariantMap> getRestoreChoices() const; |
42 | void startBackup(QStringList const& uuids) const; |
43 | + void startRestore(QStringList const& uuids) const; |
44 | |
45 | QMap<QString, QVariantMap> getState() const; |
46 | |
47 | @@ -68,6 +73,9 @@ |
48 | void readyToBackupChanged(); |
49 | void backupBusyChanged(); |
50 | |
51 | + void taskStatusChanged(QString const & displayName, QString const & status, double percentage); |
52 | + void finished(); |
53 | + |
54 | private Q_SLOTS: |
55 | void stateUpdated(); |
56 | |
57 | |
58 | === modified file 'src/cli/CMakeLists.txt' |
59 | --- src/cli/CMakeLists.txt 2016-09-06 01:31:59 +0000 |
60 | +++ src/cli/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
61 | @@ -5,6 +5,9 @@ |
62 | |
63 | set(CLI_SOURCES |
64 | main.cpp |
65 | + command-line.cpp |
66 | + command-line-client.cpp |
67 | + command-line-client-view.cpp |
68 | ) |
69 | |
70 | add_executable( |
71 | @@ -19,6 +22,7 @@ |
72 | util |
73 | qdbus-stubs |
74 | ${SERVICE_DEVEL_SF_DEPS_LIBRARIES} |
75 | + ${KEEPER_CLIENT_LIB} |
76 | Qt5::Core |
77 | Qt5::DBus |
78 | ) |
79 | |
80 | === added file 'src/cli/command-line-client-view.cpp' |
81 | --- src/cli/command-line-client-view.cpp 1970-01-01 00:00:00 +0000 |
82 | +++ src/cli/command-line-client-view.cpp 2016-12-16 09:34:32 +0000 |
83 | @@ -0,0 +1,128 @@ |
84 | +/* |
85 | + * Copyright (C) 2016 Canonical, Ltd. |
86 | + * |
87 | + * This program is free software: you can redistribute it and/or modify it |
88 | + * under the terms of the GNU General Public License version 3, as published |
89 | + * by the Free Software Foundation. |
90 | + * |
91 | + * This program is distributed in the hope that it will be useful, but |
92 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
93 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
94 | + * PURPOSE. See the GNU General Public License for more details. |
95 | + * |
96 | + * You should have received a copy of the GNU General Public License along |
97 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
98 | + * |
99 | + * Authors: |
100 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
101 | + */ |
102 | +#include "command-line-client-view.h" |
103 | + |
104 | +#include <client/client.h> |
105 | + |
106 | +#include <iostream> |
107 | +#include <iomanip> |
108 | + |
109 | +CommandLineClientView::CommandLineClientView(QObject * parent) |
110 | + : QObject(parent) |
111 | +{ |
112 | + connect(&timer_status_, &QTimer::timeout, this, &CommandLineClientView::show_info); |
113 | + |
114 | + // TODO see if we can do this in a better way |
115 | + // This line is for the global progress status and percentage |
116 | + std::cout << std::endl; |
117 | +} |
118 | + |
119 | +void CommandLineClientView::progress_changed(double percentage) |
120 | +{ |
121 | + percentage_ = percentage * 100; |
122 | +} |
123 | + |
124 | +void CommandLineClientView::status_changed(QString const & status) |
125 | +{ |
126 | + if (status_ != status) |
127 | + { |
128 | + status_ = status; |
129 | + } |
130 | +} |
131 | + |
132 | +void CommandLineClientView::add_task(QString const & display_name, QString const & initial_status, double initial_percentage) |
133 | +{ |
134 | + tasks_strings_[display_name] = get_task_string(display_name, initial_status, initial_percentage); |
135 | + // TODO see if we can do this in a better way |
136 | + // We add a line per each backup task |
137 | + std::cout << std::endl; |
138 | +} |
139 | + |
140 | +void CommandLineClientView::clear_all_tasks() |
141 | +{ |
142 | + tasks_strings_.clear(); |
143 | +} |
144 | + |
145 | +void CommandLineClientView::start_printing_tasks() |
146 | +{ |
147 | + timer_status_.start(300); |
148 | +} |
149 | + |
150 | +void CommandLineClientView::clear_all() |
151 | +{ |
152 | + timer_status_.stop(); |
153 | + std::cout << std::endl; |
154 | +} |
155 | + |
156 | +void CommandLineClientView::print_sections(QStringList const & sections) |
157 | +{ |
158 | + for (auto const & section : sections) |
159 | + { |
160 | + std::cout << section.toStdString() << std::endl; |
161 | + } |
162 | +} |
163 | + |
164 | +void CommandLineClientView::print_error_message(QString const & error_message) |
165 | +{ |
166 | + std::cerr << error_message.toStdString() << std::endl; |
167 | +} |
168 | + |
169 | +void CommandLineClientView::show_info() |
170 | +{ |
171 | + // TODO Revisit this code to see if we can do this in a different way |
172 | + // Maybe using ncurses? |
173 | + |
174 | + // Rewind to the beginning |
175 | + std::cout << '\r' << std::flush; |
176 | + // For every backup task we go up 1 line |
177 | + for (auto i = 0; i < tasks_strings_.size(); ++i) |
178 | + { |
179 | + std::cout << "\e[A"; |
180 | + } |
181 | + // print the tasks |
182 | + for (auto iter = tasks_strings_.begin(); iter != tasks_strings_.end(); ++iter) |
183 | + { |
184 | + std::cout << (*iter).toStdString() << std::setfill(' ') << std::endl; |
185 | + } |
186 | + std::cout << '\r' << std::fixed << std::setw(30) << status_.toStdString() << std::setprecision(3) |
187 | + << std::setfill(' ') << " " << percentage_ << " % " << get_next_spin_char() << " " << std::flush; |
188 | +} |
189 | + |
190 | +char CommandLineClientView::get_next_spin_char() |
191 | +{ |
192 | + char cursor[4]={'/','-','\\','|'}; |
193 | + auto ret = cursor[spin_value_]; |
194 | + spin_value_ = (spin_value_ + 1) % 4; |
195 | + return ret; |
196 | +} |
197 | + |
198 | +QString CommandLineClientView::get_task_string(QString const & displayName, QString const & status, double percentage) |
199 | +{ |
200 | + |
201 | + return QStringLiteral("%1 %2 % %3").arg(displayName, 15).arg((percentage * 100), 10, 'f', 2, ' ').arg(status, -15); |
202 | +} |
203 | + |
204 | +void CommandLineClientView::on_task_state_changed(QString const & displayName, QString const & status, double percentage) |
205 | +{ |
206 | + auto iter = tasks_strings_.find(displayName); |
207 | + if (iter != tasks_strings_.end()) |
208 | + { |
209 | + tasks_strings_[displayName] = get_task_string(displayName, status, percentage); |
210 | + } |
211 | +} |
212 | |
213 | === added file 'src/cli/command-line-client-view.h' |
214 | --- src/cli/command-line-client-view.h 1970-01-01 00:00:00 +0000 |
215 | +++ src/cli/command-line-client-view.h 2016-12-16 09:34:32 +0000 |
216 | @@ -0,0 +1,57 @@ |
217 | +/* |
218 | + * Copyright (C) 2016 Canonical, Ltd. |
219 | + * |
220 | + * This program is free software: you can redistribute it and/or modify it |
221 | + * under the terms of the GNU General Public License version 3, as published |
222 | + * by the Free Software Foundation. |
223 | + * |
224 | + * This program is distributed in the hope that it will be useful, but |
225 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
226 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
227 | + * PURPOSE. See the GNU General Public License for more details. |
228 | + * |
229 | + * You should have received a copy of the GNU General Public License along |
230 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
231 | + * |
232 | + * Authors: |
233 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
234 | + */ |
235 | +#pragma once |
236 | + |
237 | +#include <QMap> |
238 | +#include <QObject> |
239 | +#include <QTimer> |
240 | + |
241 | +class CommandLineClientView : public QObject |
242 | +{ |
243 | + Q_OBJECT |
244 | +public: |
245 | + explicit CommandLineClientView(QObject * parent = nullptr); |
246 | + ~CommandLineClientView() = default; |
247 | + |
248 | + Q_DISABLE_COPY(CommandLineClientView) |
249 | + |
250 | + void progress_changed(double percentage); |
251 | + void status_changed(QString const & status); |
252 | + |
253 | + void add_task(QString const & display_name, QString const & initial_status, double initial_percentage); |
254 | + void clear_all_tasks(); |
255 | + void start_printing_tasks(); |
256 | + void clear_all(); |
257 | + void print_sections(QStringList const & sections); |
258 | + void print_error_message(QString const & error_message); |
259 | + |
260 | +public Q_SLOTS: |
261 | + void show_info(); |
262 | + void on_task_state_changed(QString const & displayName, QString const & status, double percentage); |
263 | + |
264 | +private: |
265 | + char get_next_spin_char(); |
266 | + QString get_task_string(QString const & displayName, QString const & status, double percentage); |
267 | + |
268 | + QString status_; |
269 | + QTimer timer_status_; |
270 | + double percentage_ = 0.0; |
271 | + int spin_value_ = 0; |
272 | + QMap<QString, QString> tasks_strings_; |
273 | +}; |
274 | |
275 | === added file 'src/cli/command-line-client.cpp' |
276 | --- src/cli/command-line-client.cpp 1970-01-01 00:00:00 +0000 |
277 | +++ src/cli/command-line-client.cpp 2016-12-16 09:34:32 +0000 |
278 | @@ -0,0 +1,247 @@ |
279 | +/* |
280 | + * Copyright (C) 2016 Canonical, Ltd. |
281 | + * |
282 | + * This program is free software: you can redistribute it and/or modify it |
283 | + * under the terms of the GNU General Public License version 3, as published |
284 | + * by the Free Software Foundation. |
285 | + * |
286 | + * This program is distributed in the hope that it will be useful, but |
287 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
288 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
289 | + * PURPOSE. See the GNU General Public License for more details. |
290 | + * |
291 | + * You should have received a copy of the GNU General Public License along |
292 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
293 | + * |
294 | + * Authors: |
295 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
296 | + */ |
297 | +#include "command-line-client.h" |
298 | +#include "command-line-client-view.h" |
299 | + |
300 | +#include <client/client.h> |
301 | + |
302 | +#include <QCoreApplication> |
303 | +#include <QDebug> |
304 | + |
305 | +#include <iostream> |
306 | +#include <iomanip> |
307 | + |
308 | +CommandLineClient::CommandLineClient(QObject * parent) |
309 | + : QObject(parent) |
310 | + , keeper_client_(new KeeperClient(this)) |
311 | + , view_(new CommandLineClientView(this)) |
312 | +{ |
313 | + connect(keeper_client_.data(), &KeeperClient::statusChanged, this, &CommandLineClient::on_status_changed); |
314 | + connect(keeper_client_.data(), &KeeperClient::progressChanged, this, &CommandLineClient::on_progress_changed); |
315 | + connect(keeper_client_.data(), &KeeperClient::finished, this, &CommandLineClient::on_keeper_client_finished); |
316 | + connect(keeper_client_.data(), &KeeperClient::taskStatusChanged, view_.data(), &CommandLineClientView::on_task_state_changed); |
317 | +} |
318 | + |
319 | +CommandLineClient::~CommandLineClient() = default; |
320 | + |
321 | +void CommandLineClient::run_list_sections(bool remote) |
322 | +{ |
323 | + QMap<QString, QVariantMap> choices_values; |
324 | + if(!remote) |
325 | + { |
326 | + choices_values = keeper_client_->getBackupChoices(); |
327 | + list_backup_sections(choices_values); |
328 | + } |
329 | + else |
330 | + { |
331 | + choices_values = keeper_client_->getRestoreChoices(); |
332 | + list_restore_sections(choices_values); |
333 | + } |
334 | +} |
335 | + |
336 | +void CommandLineClient::run_backup(QStringList & sections) |
337 | +{ |
338 | + auto unhandled_sections = sections; |
339 | + auto choices_values = keeper_client_->getBackupChoices(); |
340 | + QStringList uuids; |
341 | + for(auto iter = choices_values.begin(); iter != choices_values.end() && unhandled_sections.size(); ++iter) |
342 | + { |
343 | + const auto& values = iter.value(); |
344 | + auto iter_values = values.find("type"); |
345 | + if (iter_values != values.end()) |
346 | + { |
347 | + if (iter_values.value() == "folder") |
348 | + { |
349 | + auto iter_display_name = values.find("display-name"); |
350 | + if (iter_display_name != values.end()) |
351 | + { |
352 | + auto index = unhandled_sections.indexOf((*iter_display_name).toString()); |
353 | + if (index != -1) |
354 | + { |
355 | + // we have to backup this section |
356 | + uuids << iter.key(); |
357 | + unhandled_sections.removeAt(index); |
358 | + view_->add_task((*iter_display_name).toString(), "waiting", 0.0); |
359 | + } |
360 | + } |
361 | + } |
362 | + } |
363 | + } |
364 | + |
365 | + if (!unhandled_sections.isEmpty()) |
366 | + { |
367 | + QString error_message("The following sections were not found: \n"); |
368 | + for (auto const & section : unhandled_sections) |
369 | + { |
370 | + error_message += QStringLiteral("\t %1 \n").arg(section); |
371 | + } |
372 | + view_->print_error_message(error_message); |
373 | + exit(1); |
374 | + } |
375 | + |
376 | + for (auto const & uuid: uuids) |
377 | + { |
378 | + keeper_client_->enableBackup(uuid, true); |
379 | + } |
380 | + keeper_client_->startBackup(); |
381 | + view_->start_printing_tasks(); |
382 | +} |
383 | + |
384 | +void CommandLineClient::run_restore(QStringList & sections) |
385 | +{ |
386 | + auto unhandled_sections = sections; |
387 | + auto choices_values = keeper_client_->getRestoreChoices(); |
388 | + QStringList uuids; |
389 | + for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
390 | + { |
391 | + const auto& values = iter.value(); |
392 | + |
393 | + QVariant choice_value; |
394 | + auto has_type = find_choice_value(values, "type", choice_value); |
395 | + if (has_type && choice_value == "folder") |
396 | + { |
397 | + QVariant display_name; |
398 | + auto has_display_name = find_choice_value(values, "display-name", display_name); |
399 | + if (!has_display_name) |
400 | + continue; |
401 | + |
402 | + QVariant dir_name; |
403 | + auto has_dir_name = find_choice_value(values, "dir-name", dir_name); |
404 | + if (!has_dir_name) |
405 | + continue; |
406 | + |
407 | + auto section_name = QStringLiteral("%1:%2").arg(display_name.toString()).arg(dir_name.toString()); |
408 | + auto index = unhandled_sections.indexOf(section_name); |
409 | + if (index != -1) |
410 | + { |
411 | + // we have to restore this section |
412 | + uuids << iter.key(); |
413 | + unhandled_sections.removeAt(index); |
414 | + view_->add_task(display_name.toString(), "waiting", 0.0); |
415 | + } |
416 | + } |
417 | + } |
418 | + if (!unhandled_sections.isEmpty()) |
419 | + { |
420 | + QString error_message("The following sections were not found: \n"); |
421 | + for (auto const & section : unhandled_sections) |
422 | + { |
423 | + error_message += QStringLiteral("\t %1 \n").arg(section); |
424 | + } |
425 | + view_->print_error_message(error_message); |
426 | + exit(1); |
427 | + } |
428 | + |
429 | + for (auto const & uuid: uuids) |
430 | + { |
431 | + keeper_client_->enableRestore(uuid, true); |
432 | + } |
433 | + keeper_client_->startRestore(); |
434 | + view_->start_printing_tasks(); |
435 | +} |
436 | + |
437 | +void CommandLineClient::list_backup_sections(QMap<QString, QVariantMap> const & choices_values) |
438 | +{ |
439 | + QStringList sections; |
440 | + for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
441 | + { |
442 | + const auto& values = iter.value(); |
443 | + |
444 | + QVariant choice_value; |
445 | + auto has_type = find_choice_value(values, "type", choice_value); |
446 | + if (has_type && choice_value == "folder") |
447 | + { |
448 | + auto has_display_name = find_choice_value(values, "display-name", choice_value); |
449 | + if (has_display_name) |
450 | + { |
451 | + sections << choice_value.toString(); |
452 | + } |
453 | + } |
454 | + } |
455 | + view_->print_sections(sections); |
456 | +} |
457 | + |
458 | +void CommandLineClient::list_restore_sections(QMap<QString, QVariantMap> const & choices_values) |
459 | +{ |
460 | + QMap<QString, QList<QVariantMap>> values_per_dir; |
461 | + |
462 | + for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
463 | + { |
464 | + const auto& values = iter.value(); |
465 | + |
466 | + QVariant choice_value; |
467 | + auto has_type = find_choice_value(values, "type", choice_value); |
468 | + if (has_type && choice_value == "folder") |
469 | + { |
470 | + auto has_dir_name = find_choice_value(values, "dir-name", choice_value); |
471 | + if (!has_dir_name) |
472 | + continue; |
473 | + values_per_dir[choice_value.toString()].push_back(values); |
474 | + } |
475 | + } |
476 | + |
477 | + QStringList sections; |
478 | + for(auto iter = values_per_dir.begin(); iter != values_per_dir.end(); ++iter) |
479 | + { |
480 | + for(auto iter_items = (*iter).begin(); iter_items != (*iter).end(); ++iter_items) |
481 | + { |
482 | + const auto& values = (*iter_items); |
483 | + |
484 | + QVariant choice_value; |
485 | + auto has_type = find_choice_value(values, "type", choice_value); |
486 | + if (has_type && choice_value == "folder") |
487 | + { |
488 | + auto has_display_name = find_choice_value(values, "display-name", choice_value); |
489 | + if (has_display_name) |
490 | + { |
491 | + sections << QStringLiteral("%1:%2").arg(choice_value.toString()).arg(iter.key()); |
492 | + } |
493 | + } |
494 | + } |
495 | + sections << ""; |
496 | + } |
497 | + view_->print_sections(sections); |
498 | +} |
499 | + |
500 | +void CommandLineClient::on_progress_changed() |
501 | +{ |
502 | + view_->progress_changed(keeper_client_->progress()); |
503 | +} |
504 | + |
505 | +void CommandLineClient::on_status_changed() |
506 | +{ |
507 | + view_->status_changed(keeper_client_->status()); |
508 | +} |
509 | + |
510 | +void CommandLineClient::on_keeper_client_finished() |
511 | +{ |
512 | + QCoreApplication::processEvents(); |
513 | + view_->show_info(); |
514 | + view_->clear_all(); |
515 | + QCoreApplication::exit(0); |
516 | +} |
517 | + |
518 | +bool CommandLineClient::find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value) |
519 | +{ |
520 | + auto iter = choice.find(id); |
521 | + if (iter == choice.end()) |
522 | + return false; |
523 | + value = (*iter); |
524 | + return true; |
525 | +} |
526 | |
527 | === added file 'src/cli/command-line-client.h' |
528 | --- src/cli/command-line-client.h 1970-01-01 00:00:00 +0000 |
529 | +++ src/cli/command-line-client.h 2016-12-16 09:34:32 +0000 |
530 | @@ -0,0 +1,53 @@ |
531 | +/* |
532 | + * Copyright (C) 2016 Canonical, Ltd. |
533 | + * |
534 | + * This program is free software: you can redistribute it and/or modify it |
535 | + * under the terms of the GNU General Public License version 3, as published |
536 | + * by the Free Software Foundation. |
537 | + * |
538 | + * This program is distributed in the hope that it will be useful, but |
539 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
540 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
541 | + * PURPOSE. See the GNU General Public License for more details. |
542 | + * |
543 | + * You should have received a copy of the GNU General Public License along |
544 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
545 | + * |
546 | + * Authors: |
547 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
548 | + */ |
549 | +#pragma once |
550 | + |
551 | +#include <QMap> |
552 | +#include <QObject> |
553 | +#include <QScopedPointer> |
554 | +#include <QTimer> |
555 | + |
556 | +class KeeperClient; |
557 | +class CommandLineClientView; |
558 | + |
559 | +class CommandLineClient : public QObject |
560 | +{ |
561 | + Q_OBJECT |
562 | +public: |
563 | + explicit CommandLineClient(QObject * parent = nullptr); |
564 | + ~CommandLineClient(); |
565 | + |
566 | + Q_DISABLE_COPY(CommandLineClient) |
567 | + |
568 | + void run_list_sections(bool remote); |
569 | + void run_backup(QStringList & sections); |
570 | + void run_restore(QStringList & sections); |
571 | + |
572 | +private Q_SLOTS: |
573 | + void on_progress_changed(); |
574 | + void on_status_changed(); |
575 | + void on_keeper_client_finished(); |
576 | + |
577 | +private: |
578 | + static bool find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value); |
579 | + void list_backup_sections(QMap<QString, QVariantMap> const & choices); |
580 | + void list_restore_sections(QMap<QString, QVariantMap> const & choices); |
581 | + QScopedPointer<KeeperClient> keeper_client_; |
582 | + QScopedPointer<CommandLineClientView> view_; |
583 | +}; |
584 | |
585 | === added file 'src/cli/command-line.cpp' |
586 | --- src/cli/command-line.cpp 1970-01-01 00:00:00 +0000 |
587 | +++ src/cli/command-line.cpp 2016-12-16 09:34:32 +0000 |
588 | @@ -0,0 +1,188 @@ |
589 | +/* |
590 | + * Copyright (C) 2016 Canonical, Ltd. |
591 | + * |
592 | + * This program is free software: you can redistribute it and/or modify it |
593 | + * under the terms of the GNU General Public License version 3, as published |
594 | + * by the Free Software Foundation. |
595 | + * |
596 | + * This program is distributed in the hope that it will be useful, but |
597 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
598 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
599 | + * PURPOSE. See the GNU General Public License for more details. |
600 | + * |
601 | + * You should have received a copy of the GNU General Public License along |
602 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
603 | + * |
604 | + * Authors: |
605 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
606 | + */ |
607 | +#include "command-line.h" |
608 | + |
609 | +#include <QCommandLineParser> |
610 | +#include <QDebug> |
611 | + |
612 | +#include <iostream> |
613 | + |
614 | +namespace |
615 | +{ |
616 | + // arguments |
617 | + constexpr const char ARGUMENT_LIST_SECTIONS[] = "list-sections"; |
618 | + constexpr const char ARGUMENT_BACKUP[] = "backup"; |
619 | + constexpr const char ARGUMENT_RESTORE[] = "restore"; |
620 | + |
621 | + // argument descriptions |
622 | + constexpr const char ARGUMENT_LIST_SECTIONS_DESCRIPTION[] = "List the sections available to backup"; |
623 | + constexpr const char ARGUMENT_BACKUP_DESCRIPTION[] = "Starts a backup"; |
624 | + constexpr const char ARGUMENT_RESTORE_DESCRIPTION[] = "Starts a restore"; |
625 | + |
626 | + // options |
627 | + constexpr const char OPTION_STORAGE[] = "storage"; |
628 | + constexpr const char OPTION_SECTIONS[] = "sections"; |
629 | + |
630 | + // option descriptions |
631 | + constexpr const char OPTION_STORAGE_DESCRIPTION[] = "Lists the available sections stored at the storage"; |
632 | + constexpr const char OPTION_SECTIONS_DESCRIPTION[] = "Lists the sections to backup or restore"; |
633 | +} |
634 | + |
635 | +CommandLineParser::CommandLineParser() |
636 | + : parser_(new QCommandLineParser) |
637 | +{ |
638 | + parser_->setApplicationDescription("Keeper command line client"); |
639 | + parser_->addHelpOption(); |
640 | + parser_->addVersionOption(); |
641 | + parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION)); |
642 | + parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION)); |
643 | + parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION)); |
644 | +} |
645 | + |
646 | +bool CommandLineParser::parse(QStringList const & arguments, QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
647 | +{ |
648 | + parser_->parse(arguments); |
649 | + const QStringList args = parser_->positionalArguments(); |
650 | + if (!check_number_of_args(args)) |
651 | + { |
652 | + return false; |
653 | + } |
654 | + |
655 | + if (args.size() == 1) |
656 | + { |
657 | + // if something fails at the process call the process exists |
658 | + if (args.at(0) == ARGUMENT_LIST_SECTIONS) |
659 | + { |
660 | + return handle_list_sections(app, cmd_args); |
661 | + } |
662 | + else if (args.at(0) == ARGUMENT_BACKUP) |
663 | + { |
664 | + return handle_backup(app, cmd_args); |
665 | + } |
666 | + else if (args.at(0) == ARGUMENT_RESTORE) |
667 | + { |
668 | + return handle_restore(app, cmd_args); |
669 | + } |
670 | + else |
671 | + { |
672 | + std::cerr << "Bad argument." << std::endl; |
673 | + std::cerr << parser_->errorText().toStdString() << std::endl; |
674 | + exit(1); |
675 | + } |
676 | + } |
677 | + else |
678 | + { |
679 | + qDebug() << "More or none arguments"; |
680 | + // maybe we have the version or help options |
681 | + parser_->process(app); |
682 | + } |
683 | + |
684 | + return false; |
685 | +} |
686 | + |
687 | +bool CommandLineParser::handle_list_sections(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
688 | +{ |
689 | + parser_->clearPositionalArguments(); |
690 | + parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION)); |
691 | + |
692 | + parser_->addOptions({ |
693 | + {{"r", OPTION_STORAGE}, |
694 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION)}, |
695 | + }); |
696 | + parser_->process(app); |
697 | + |
698 | + // it didn't exit... we're good |
699 | + cmd_args.sections.clear(); |
700 | + cmd_args.storage.clear(); |
701 | + if (parser_->isSet(OPTION_STORAGE)) |
702 | + { |
703 | + cmd_args.cmd = CommandLineParser::Command::LIST_REMOTE_SECTIONS; |
704 | + } |
705 | + else |
706 | + { |
707 | + cmd_args.cmd = CommandLineParser::Command::LIST_LOCAL_SECTIONS; |
708 | + } |
709 | + |
710 | + return true; |
711 | +} |
712 | + |
713 | +bool CommandLineParser::handle_backup(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
714 | +{ |
715 | + parser_->clearPositionalArguments(); |
716 | + parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION)); |
717 | + |
718 | + parser_->addOptions({ |
719 | + {{"s", OPTION_SECTIONS}, |
720 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION), |
721 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION) |
722 | + }, |
723 | + }); |
724 | + parser_->process(app); |
725 | + |
726 | + // it didn't exit... we're good |
727 | + cmd_args.sections.clear(); |
728 | + cmd_args.storage.clear(); |
729 | + cmd_args.cmd = CommandLineParser::Command::BACKUP; |
730 | + if (!parser_->isSet(OPTION_SECTIONS)) |
731 | + { |
732 | + std::cerr << "You need to specify some sections to run a backup." << std::endl; |
733 | + return false; |
734 | + } |
735 | + cmd_args.sections = parser_->value(OPTION_SECTIONS).split(','); |
736 | + |
737 | + return true; |
738 | +} |
739 | + |
740 | +bool CommandLineParser::handle_restore(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
741 | +{ |
742 | + parser_->clearPositionalArguments(); |
743 | + parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION)); |
744 | + |
745 | + parser_->addOptions({ |
746 | + {{"s", OPTION_SECTIONS}, |
747 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION), |
748 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION) |
749 | + }, |
750 | + }); |
751 | + parser_->process(app); |
752 | + |
753 | + // it didn't exit... we're good |
754 | + cmd_args.sections = QStringList(); |
755 | + cmd_args.storage = QString(); |
756 | + cmd_args.cmd = CommandLineParser::Command::RESTORE; |
757 | + if (!parser_->isSet(OPTION_SECTIONS)) |
758 | + { |
759 | + std::cerr << "You need to specify some sections to run a restore." << std::endl; |
760 | + return false; |
761 | + } |
762 | + cmd_args.sections = parser_->value(OPTION_SECTIONS).split(','); |
763 | + |
764 | + return true; |
765 | +} |
766 | + |
767 | +bool CommandLineParser::check_number_of_args(QStringList const & args) |
768 | +{ |
769 | + if (args.size() > 1) |
770 | + { |
771 | + std::cerr << "Please, pass only one argument." << std::endl; |
772 | + std::cerr << parser_->helpText().toStdString() << std::endl; |
773 | + return false; |
774 | + } |
775 | + return true; |
776 | +} |
777 | |
778 | === added file 'src/cli/command-line.h' |
779 | --- src/cli/command-line.h 1970-01-01 00:00:00 +0000 |
780 | +++ src/cli/command-line.h 2016-12-16 09:34:32 +0000 |
781 | @@ -0,0 +1,52 @@ |
782 | +/* |
783 | + * Copyright (C) 2016 Canonical, Ltd. |
784 | + * |
785 | + * This program is free software: you can redistribute it and/or modify it |
786 | + * under the terms of the GNU General Public License version 3, as published |
787 | + * by the Free Software Foundation. |
788 | + * |
789 | + * This program is distributed in the hope that it will be useful, but |
790 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
791 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
792 | + * PURPOSE. See the GNU General Public License for more details. |
793 | + * |
794 | + * You should have received a copy of the GNU General Public License along |
795 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
796 | + * |
797 | + * Authors: |
798 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
799 | + */ |
800 | +#pragma once |
801 | + |
802 | +#include <QCoreApplication> |
803 | +#include <QSharedPointer> |
804 | + |
805 | +class QCommandLineParser; |
806 | + |
807 | +class CommandLineParser |
808 | +{ |
809 | +public: |
810 | + Q_ENUMS(Command) |
811 | + enum class Command {LIST_LOCAL_SECTIONS, LIST_REMOTE_SECTIONS, BACKUP, RESTORE}; |
812 | + struct CommandArgs |
813 | + { |
814 | + Command cmd; |
815 | + QStringList sections; |
816 | + QString storage; |
817 | + }; |
818 | + |
819 | + CommandLineParser(); |
820 | + ~CommandLineParser() = default; |
821 | + Q_DISABLE_COPY(CommandLineParser) |
822 | + |
823 | + bool parse(QStringList const & arguments, QCoreApplication const & app, CommandArgs & cmd_args); |
824 | + |
825 | +private: |
826 | + bool handle_list_sections(QCoreApplication const & app, CommandArgs & cmd_args); |
827 | + bool handle_backup(QCoreApplication const & app, CommandArgs & cmd_args); |
828 | + bool handle_restore(QCoreApplication const & app, CommandArgs & cmd_args); |
829 | + |
830 | + bool check_number_of_args(QStringList const & args); |
831 | + |
832 | + QSharedPointer<QCommandLineParser> parser_; |
833 | +}; |
834 | |
835 | === modified file 'src/cli/main.cpp' |
836 | --- src/cli/main.cpp 2016-11-22 09:37:40 +0000 |
837 | +++ src/cli/main.cpp 2016-12-16 09:34:32 +0000 |
838 | @@ -17,6 +17,8 @@ |
839 | * Charles Kerr <charles.kerr@canonical.com> |
840 | * Xavi Garcia <xavi.garcia.mena@canonical.com> |
841 | */ |
842 | +#include "command-line.h" |
843 | +#include "command-line-client.h" |
844 | |
845 | #include <dbus-types.h> |
846 | #include <util/logging.h> |
847 | @@ -29,6 +31,8 @@ |
848 | #include <libintl.h> |
849 | #include <cstdlib> |
850 | #include <ctime> |
851 | +#include <iostream> |
852 | + |
853 | |
854 | int |
855 | main(int argc, char **argv) |
856 | @@ -37,7 +41,6 @@ |
857 | |
858 | QCoreApplication app(argc, argv); |
859 | DBusTypes::registerMetaTypes(); |
860 | -// Variant::registerMetaTypes(); |
861 | std::srand(unsigned(std::time(nullptr))); |
862 | |
863 | // boilerplate locale |
864 | @@ -46,51 +49,31 @@ |
865 | bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); |
866 | textdomain(GETTEXT_PACKAGE); |
867 | |
868 | - if (argc == 2 && QString("--print-address") == argv[1]) |
869 | - { |
870 | - qDebug() << QDBusConnection::sessionBus().baseService(); |
871 | - } |
872 | - |
873 | - qDebug() << "Argc =" << argc; |
874 | - if (argc == 2 && QString("--use-uuids") == argv[1]) |
875 | - { |
876 | - QScopedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser( |
877 | - DBusTypes::KEEPER_SERVICE, |
878 | - DBusTypes::KEEPER_USER_PATH, |
879 | - QDBusConnection::sessionBus() |
880 | - ) ); |
881 | - QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices"); |
882 | - if (!choices.isValid()) |
883 | - { |
884 | - qWarning() << "Error getting backup choices:" << choices.error().message(); |
885 | - } |
886 | - |
887 | - QStringList uuids; |
888 | - auto choices_values = choices.value(); |
889 | - for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
890 | - { |
891 | - const auto& values = iter.value(); |
892 | - auto iter_values = values.find("type"); |
893 | - if (iter_values != values.end()) |
894 | - { |
895 | - if (iter_values.value().toString() == "folder") |
896 | - { |
897 | - qDebug() << "Adding uuid" << iter.key() << "with type:" << "folder"; |
898 | - uuids << iter.key(); |
899 | - } |
900 | - } |
901 | - } |
902 | - |
903 | - QDBusReply<void> backup_reply = user_iface->call("StartBackup", uuids); |
904 | - |
905 | - if (!backup_reply.isValid()) |
906 | - { |
907 | - qWarning() << "Error starting backup:" << backup_reply.error().message(); |
908 | - } |
909 | - } |
910 | - else |
911 | - { |
912 | - qWarning() << "FIXME"; |
913 | + QCoreApplication::setApplicationName("keeper"); |
914 | + QCoreApplication::setApplicationVersion("1.0"); |
915 | + |
916 | + CommandLineParser parser; |
917 | + CommandLineClient client; |
918 | + CommandLineParser::CommandArgs cmd_args; |
919 | + if (parser.parse(QCoreApplication::arguments(), app, cmd_args)) |
920 | + { |
921 | + switch(cmd_args.cmd) |
922 | + { |
923 | + case CommandLineParser::Command::LIST_LOCAL_SECTIONS: |
924 | + client.run_list_sections(false); |
925 | + exit(0); |
926 | + break; |
927 | + case CommandLineParser::Command::LIST_REMOTE_SECTIONS: |
928 | + client.run_list_sections(true); |
929 | + exit(0); |
930 | + break; |
931 | + case CommandLineParser::Command::BACKUP: |
932 | + client.run_backup(cmd_args.sections); |
933 | + break; |
934 | + case CommandLineParser::Command::RESTORE: |
935 | + client.run_restore(cmd_args.sections); |
936 | + break; |
937 | + }; |
938 | } |
939 | |
940 | |
941 | |
942 | === modified file 'src/client/CMakeLists.txt' |
943 | --- src/client/CMakeLists.txt 2016-08-26 09:30:11 +0000 |
944 | +++ src/client/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
945 | @@ -11,6 +11,11 @@ |
946 | ${CLIENT_HEADERS} |
947 | ) |
948 | |
949 | +set_target_properties(${KEEPER_CLIENT_LIB} PROPERTIES |
950 | + AUTOMOC TRUE |
951 | + LINK_FLAGS "-Wl,--no-undefined" |
952 | +) |
953 | + |
954 | target_link_libraries( |
955 | ${KEEPER_CLIENT_LIB} |
956 | qdbus-stubs |
957 | |
958 | === modified file 'src/client/client.cpp' |
959 | --- src/client/client.cpp 2016-08-26 08:48:05 +0000 |
960 | +++ src/client/client.cpp 2016-12-16 09:34:32 +0000 |
961 | @@ -22,34 +22,62 @@ |
962 | #include <client/client.h> |
963 | |
964 | #include <qdbus-stubs/keeper_user_interface.h> |
965 | +#include <qdbus-stubs/DBusPropertiesInterface.h> |
966 | |
967 | struct KeeperClientPrivate final |
968 | { |
969 | Q_DISABLE_COPY(KeeperClientPrivate) |
970 | |
971 | - KeeperClientPrivate(QObject* parent) |
972 | + enum class TasksMode { IDLE_MODE, BACKUP_MODE, RESTORE_MODE }; |
973 | + |
974 | + explicit KeeperClientPrivate(QObject* /* parent */) |
975 | : userIface(new DBusInterfaceKeeperUser( |
976 | DBusTypes::KEEPER_SERVICE, |
977 | DBusTypes::KEEPER_USER_PATH, |
978 | QDBusConnection::sessionBus() |
979 | - )), |
980 | - status(""), |
981 | - progress(0), |
982 | - readyToBackup(false), |
983 | - backupBusy(false), |
984 | - stateTimer(parent) |
985 | + )) |
986 | + , propertiesIface(new DBusPropertiesInterface( |
987 | + DBusTypes::KEEPER_SERVICE, |
988 | + DBusTypes::KEEPER_USER_PATH, |
989 | + QDBusConnection::sessionBus() |
990 | + )) |
991 | { |
992 | } |
993 | |
994 | ~KeeperClientPrivate() = default; |
995 | |
996 | + struct TaskStatus |
997 | + { |
998 | + QString status; |
999 | + double percentage; |
1000 | + }; |
1001 | + |
1002 | + static bool stateIsFinal(QString const & stateString) |
1003 | + { |
1004 | + return (stateString == "complete" || stateString == "cancelled" || stateString == "failed"); |
1005 | + } |
1006 | + |
1007 | + static bool checkAllTasksFinished(QMap<QString, QVariantMap> const & state) |
1008 | + { |
1009 | + bool ret = true; |
1010 | + for (auto iter = state.begin(); ret && (iter != state.end()); ++iter) |
1011 | + { |
1012 | + auto statusString = (*iter).value("action").toString(); |
1013 | + ret = stateIsFinal(statusString); |
1014 | + } |
1015 | + return ret; |
1016 | + } |
1017 | + |
1018 | QScopedPointer<DBusInterfaceKeeperUser> userIface; |
1019 | + QScopedPointer<DBusPropertiesInterface> propertiesIface; |
1020 | QString status; |
1021 | QMap<QString, QVariantMap> backups; |
1022 | - double progress; |
1023 | - bool readyToBackup; |
1024 | - bool backupBusy; |
1025 | - QTimer stateTimer; |
1026 | + QMap<QString, QVariantMap> restores; |
1027 | + double progress = 0; |
1028 | + bool readyToBackup = false; |
1029 | + bool backupBusy = false; |
1030 | + QMap<QString, TaskStatus> task_status; |
1031 | + TasksMode mode = TasksMode::IDLE_MODE; |
1032 | }; |
1033 | |
1034 | KeeperClient::KeeperClient(QObject* parent) : |
1035 | @@ -66,7 +94,7 @@ |
1036 | iter.value()["enabled"] = false; |
1037 | } |
1038 | |
1039 | - connect(&d->stateTimer, &QTimer::timeout, this, &KeeperClient::stateUpdated); |
1040 | + connect(d->propertiesIface.data(), &DBusPropertiesInterface::PropertiesChanged, this, &KeeperClient::stateUpdated); |
1041 | } |
1042 | |
1043 | KeeperClient::~KeeperClient() = default; |
1044 | @@ -120,17 +148,19 @@ |
1045 | } |
1046 | } |
1047 | |
1048 | + d->task_status[uuid] = KeeperClientPrivate::TaskStatus{"", 0.0}; |
1049 | + |
1050 | Q_EMIT readyToBackupChanged(); |
1051 | } |
1052 | |
1053 | +void KeeperClient::enableRestore(QString uuid, bool enabled) |
1054 | +{ |
1055 | + // Until we re-design the client we treat restores as backups |
1056 | + enableBackup(uuid, enabled); |
1057 | +} |
1058 | + |
1059 | void KeeperClient::startBackup() |
1060 | { |
1061 | - // TODO: Instead of polling for state, we should be listening to a stateChanged signal |
1062 | - if (!d->stateTimer.isActive()) |
1063 | - { |
1064 | - d->stateTimer.start(200); |
1065 | - } |
1066 | - |
1067 | // Determine which backups are enabled, and start only those |
1068 | QStringList backupList; |
1069 | for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1070 | @@ -145,6 +175,7 @@ |
1071 | { |
1072 | startBackup(backupList); |
1073 | |
1074 | + d->mode = KeeperClientPrivate::TasksMode::BACKUP_MODE; |
1075 | d->status = "Preparing Backup..."; |
1076 | Q_EMIT statusChanged(); |
1077 | d->backupBusy = true; |
1078 | @@ -152,6 +183,30 @@ |
1079 | } |
1080 | } |
1081 | |
1082 | +void KeeperClient::startRestore() |
1083 | +{ |
1084 | + // Determine which restores are enabled, and start only those |
1085 | + QStringList restoreList; |
1086 | + for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1087 | + { |
1088 | + if (iter.value().value("enabled").toBool()) |
1089 | + { |
1090 | + restoreList.append(iter.key()); |
1091 | + } |
1092 | + } |
1093 | + |
1094 | + if (!restoreList.empty()) |
1095 | + { |
1096 | + startRestore(restoreList); |
1097 | + |
1098 | + d->mode = KeeperClientPrivate::TasksMode::RESTORE_MODE; |
1099 | + d->status = "Preparing Restore..."; |
1100 | + Q_EMIT statusChanged(); |
1101 | + d->backupBusy = true; |
1102 | + Q_EMIT backupBusyChanged(); |
1103 | + } |
1104 | +} |
1105 | + |
1106 | QString KeeperClient::getBackupName(QString uuid) |
1107 | { |
1108 | return d->backups.value(uuid).value("display-name").toString(); |
1109 | @@ -170,6 +225,20 @@ |
1110 | return choices.value(); |
1111 | } |
1112 | |
1113 | +QMap<QString, QVariantMap> KeeperClient::getRestoreChoices() const |
1114 | +{ |
1115 | + QDBusPendingReply<QMap<QString, QVariantMap>> choices = d->userIface->call("GetRestoreChoices"); |
1116 | + |
1117 | + choices.waitForFinished(); |
1118 | + if (!choices.isValid()) |
1119 | + { |
1120 | + qWarning() << "Error getting restore choices:" << choices.error().message(); |
1121 | + return QMap<QString, QVariantMap>(); |
1122 | + } |
1123 | + |
1124 | + return choices.value(); |
1125 | +} |
1126 | + |
1127 | void KeeperClient::startBackup(const QStringList& uuids) const |
1128 | { |
1129 | QDBusReply<void> backupReply = d->userIface->call("StartBackup", uuids); |
1130 | @@ -180,6 +249,16 @@ |
1131 | } |
1132 | } |
1133 | |
1134 | +void KeeperClient::startRestore(const QStringList& uuids) const |
1135 | +{ |
1136 | + QDBusReply<void> backupReply = d->userIface->call("StartRestore", uuids); |
1137 | + |
1138 | + if (!backupReply.isValid()) |
1139 | + { |
1140 | + qWarning() << "Error starting restore:" << backupReply.error().message(); |
1141 | + } |
1142 | +} |
1143 | + |
1144 | QMap<QString, QVariantMap> KeeperClient::getState() const |
1145 | { |
1146 | return d->userIface->state(); |
1147 | @@ -191,9 +270,26 @@ |
1148 | |
1149 | if (!states.empty()) |
1150 | { |
1151 | - // Calculate current total progress |
1152 | - // TODO: May be better to monitor each backup's progress separately instead of total |
1153 | - // to avoid irregular jumps in progress between larger and smaller backups |
1154 | + for (auto const & uuid : d->task_status.keys()) |
1155 | + { |
1156 | + auto iter_state = states.find(uuid); |
1157 | + if (iter_state == states.end()) |
1158 | + { |
1159 | + qWarning() << "State for uuid: " << uuid << " was not found"; |
1160 | + } |
1161 | + auto state = (*iter_state); |
1162 | + double progress = state.value("percent-done").toDouble(); |
1163 | + auto status = state.value("action").toString(); |
1164 | + |
1165 | + auto current_state = d->task_status[uuid]; |
1166 | + if (current_state.status != status || current_state.percentage < progress) |
1167 | + { |
1168 | + d->task_status[uuid].status = status; |
1169 | + d->task_status[uuid].percentage = progress; |
1170 | + Q_EMIT(taskStatusChanged(state.value("display-name").toString(), status, progress)); |
1171 | + } |
1172 | + } |
1173 | + |
1174 | double totalProgress = 0; |
1175 | for (auto const& state : states) |
1176 | { |
1177 | @@ -203,28 +299,45 @@ |
1178 | d->progress = totalProgress / states.count(); |
1179 | Q_EMIT progressChanged(); |
1180 | |
1181 | + auto allTasksFinished = d->checkAllTasksFinished(states); |
1182 | // Update backup status |
1183 | + QString statusString; |
1184 | + if (d->mode == KeeperClientPrivate::TasksMode::BACKUP_MODE) |
1185 | + { |
1186 | + statusString = QStringLiteral("Backup"); |
1187 | + } |
1188 | + else if (d->mode == KeeperClientPrivate::TasksMode::RESTORE_MODE) |
1189 | + { |
1190 | + statusString = QStringLiteral("Restore"); |
1191 | + } |
1192 | if (d->progress > 0 && d->progress < 1) |
1193 | { |
1194 | - d->status = "Backup In Progress..."; |
1195 | - Q_EMIT statusChanged(); |
1196 | - |
1197 | - d->backupBusy = true; |
1198 | - Q_EMIT backupBusyChanged(); |
1199 | - } |
1200 | - else if (d->progress >= 1) |
1201 | - { |
1202 | - d->status = "Backup Complete"; |
1203 | + d->status = statusString + QStringLiteral(" In Progress..."); |
1204 | + Q_EMIT statusChanged(); |
1205 | + |
1206 | + d->backupBusy = true; |
1207 | + Q_EMIT backupBusyChanged(); |
1208 | + } |
1209 | + else if (d->progress >= 1 && !allTasksFinished) |
1210 | + { |
1211 | + d->status = statusString + QStringLiteral(" Finishing..."); |
1212 | + Q_EMIT statusChanged(); |
1213 | + |
1214 | + d->backupBusy = true; |
1215 | + Q_EMIT backupBusyChanged(); |
1216 | + } |
1217 | + else if (allTasksFinished) |
1218 | + { |
1219 | + d->status = statusString + QStringLiteral(" Complete"); |
1220 | Q_EMIT statusChanged(); |
1221 | |
1222 | d->backupBusy = false; |
1223 | Q_EMIT backupBusyChanged(); |
1224 | + } |
1225 | |
1226 | - // Stop state timer |
1227 | - if (d->stateTimer.isActive()) |
1228 | - { |
1229 | - d->stateTimer.stop(); |
1230 | - } |
1231 | + if (d->checkAllTasksFinished(states)) |
1232 | + { |
1233 | + Q_EMIT(finished()); |
1234 | } |
1235 | } |
1236 | } |
1237 | |
1238 | === modified file 'src/helper/CMakeLists.txt' |
1239 | --- src/helper/CMakeLists.txt 2016-11-11 14:50:06 +0000 |
1240 | +++ src/helper/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
1241 | @@ -18,6 +18,21 @@ |
1242 | ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR} |
1243 | ) |
1244 | |
1245 | +set( |
1246 | + FOLDER_RESTORE |
1247 | + folder-restore.sh |
1248 | +) |
1249 | +configure_file( |
1250 | + ${CMAKE_CURRENT_SOURCE_DIR}/${FOLDER_RESTORE}.in |
1251 | + ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE} |
1252 | +) |
1253 | + |
1254 | +install( |
1255 | + PROGRAMS |
1256 | + ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE} |
1257 | + DESTINATION |
1258 | + ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR} |
1259 | +) |
1260 | |
1261 | # |
1262 | # the library |
1263 | |
1264 | === added file 'src/helper/folder-restore.sh.in' |
1265 | --- src/helper/folder-restore.sh.in 1970-01-01 00:00:00 +0000 |
1266 | +++ src/helper/folder-restore.sh.in 2016-12-16 09:34:32 +0000 |
1267 | @@ -0,0 +1,23 @@ |
1268 | +#!/bin/bash |
1269 | +# |
1270 | +# Copyright (C) 2016 Canonical, Ltd. |
1271 | +# |
1272 | +# This program is free software: you can redistribute it and/or modify it |
1273 | +# under the terms of the GNU General Public License version 3, as published |
1274 | +# by the Free Software Foundation. |
1275 | +# |
1276 | +# This program is distributed in the hope that it will be useful, but |
1277 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1278 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1279 | +# PURPOSE. See the GNU General Public License for more details. |
1280 | +# |
1281 | +# You should have received a copy of the GNU General Public License along |
1282 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1283 | +# |
1284 | +# Authors: |
1285 | +# Xavi Garcia <xavi.garcia.mena@canonical.com> |
1286 | +# Charles Kerr <charles.kerr@canonical.com> |
1287 | +# |
1288 | + |
1289 | +echo $PWD |
1290 | +# TODO, please place here your restore helper code. |
1291 | |
1292 | === modified file 'src/helper/restore-helper.cpp' |
1293 | --- src/helper/restore-helper.cpp 2016-11-22 09:37:40 +0000 |
1294 | +++ src/helper/restore-helper.cpp 2016-12-16 09:34:32 +0000 |
1295 | @@ -100,6 +100,11 @@ |
1296 | std::bind(&RestoreHelperPrivate::on_ready_read, this) |
1297 | ); |
1298 | |
1299 | + // TODO investigate why UAL takes so long to call the helper started callback |
1300 | + // At this point we are sure that the helper started, as it is the helper |
1301 | + // the ones that asks for a downloader socket. |
1302 | + q_ptr->Helper::on_helper_started(); |
1303 | + |
1304 | // maybe there's data already to be read |
1305 | process_more(); |
1306 | |
1307 | |
1308 | === modified file 'src/qdbus-stubs/CMakeLists.txt' |
1309 | --- src/qdbus-stubs/CMakeLists.txt 2016-08-10 05:41:26 +0000 |
1310 | +++ src/qdbus-stubs/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
1311 | @@ -84,6 +84,23 @@ |
1312 | KeeperUserAdaptor |
1313 | ) |
1314 | |
1315 | +set( |
1316 | + properties_xml |
1317 | + "org.freedesktop.DBus.Properties.xml" |
1318 | +) |
1319 | + |
1320 | +set_source_files_properties( |
1321 | + "${properties_xml}" |
1322 | + PROPERTIES |
1323 | + NO_NAMESPACE YES |
1324 | + CLASSNAME DBusPropertiesInterface |
1325 | +) |
1326 | + |
1327 | +qt5_add_dbus_interface( |
1328 | + interface_files |
1329 | + ${properties_xml} |
1330 | + DBusPropertiesInterface |
1331 | +) |
1332 | # |
1333 | # |
1334 | |
1335 | @@ -99,7 +116,7 @@ |
1336 | ${adaptor_files} |
1337 | ) |
1338 | |
1339 | -target_link_libraries( |
1340 | - ${STUBS_LIB} |
1341 | - backup-helper |
1342 | -) |
1343 | +#target_link_libraries( |
1344 | +# ${STUBS_LIB} |
1345 | +# backup-helper |
1346 | +#) |
1347 | |
1348 | === modified file 'src/qdbus-stubs/dbus-types.h' |
1349 | --- src/qdbus-stubs/dbus-types.h 2016-07-14 15:31:11 +0000 |
1350 | +++ src/qdbus-stubs/dbus-types.h 2016-12-16 09:34:32 +0000 |
1351 | @@ -22,7 +22,6 @@ |
1352 | #include <QtCore> |
1353 | #include <QString> |
1354 | #include <QVariantMap> |
1355 | -#include <helper/helper.h> |
1356 | |
1357 | typedef QMap<QString, QVariantMap> QVariantDictMap; |
1358 | Q_DECLARE_METATYPE(QVariantDictMap) |
1359 | @@ -39,7 +38,7 @@ |
1360 | |
1361 | qDBusRegisterMetaType<QVariantDictMap>(); |
1362 | qDBusRegisterMetaType<QStringMap>(); |
1363 | - Helper::registerMetaTypes(); |
1364 | +// Helper::registerMetaTypes(); |
1365 | } |
1366 | |
1367 | constexpr const char KEEPER_SERVICE[] = "com.canonical.keeper"; |
1368 | |
1369 | === added file 'src/qdbus-stubs/org.freedesktop.DBus.Properties.xml' |
1370 | --- src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000 |
1371 | +++ src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 2016-12-16 09:34:32 +0000 |
1372 | @@ -0,0 +1,27 @@ |
1373 | +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" |
1374 | + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
1375 | +<node> |
1376 | + <interface name="org.freedesktop.DBus.Properties"> |
1377 | + <method name="Get"> |
1378 | + <arg type="s" name="interface_name" direction="in"/> |
1379 | + <arg type="s" name="property_name" direction="in"/> |
1380 | + <arg type="v" name="value" direction="out"/> |
1381 | + </method> |
1382 | + <method name="GetAll"> |
1383 | + <arg type="s" name="interface_name" direction="in"/> |
1384 | + <arg type="a{sv}" name="properties" direction="out"/> |
1385 | + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> |
1386 | + </method> |
1387 | + <method name="Set"> |
1388 | + <arg type="s" name="interface_name" direction="in"/> |
1389 | + <arg type="s" name="property_name" direction="in"/> |
1390 | + <arg type="v" name="value" direction="in"/> |
1391 | + </method> |
1392 | + <signal name="PropertiesChanged"> |
1393 | + <arg type="s" name="interface_name"/> |
1394 | + <arg type="a{sv}" name="changed_properties"/> |
1395 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
1396 | + <arg type="as" name="invalidated_properties"/> |
1397 | + </signal> |
1398 | + </interface> |
1399 | +</node> |
1400 | |
1401 | === modified file 'src/service/keeper.cpp' |
1402 | --- src/service/keeper.cpp 2016-11-22 09:37:40 +0000 |
1403 | +++ src/service/keeper.cpp 2016-12-16 09:34:32 +0000 |
1404 | @@ -75,6 +75,9 @@ |
1405 | , restore_choices_(restore_choices) |
1406 | , task_manager_{helper_registry, storage_} |
1407 | { |
1408 | + QObject::connect(&task_manager_, &TaskManager::finished, |
1409 | + std::bind(&KeeperPrivate::on_task_manager_finished, this) |
1410 | + ); |
1411 | } |
1412 | |
1413 | enum class ChoicesType { BACKUP_CHOICES, RESTORES_CHOICES }; |
1414 | @@ -213,6 +216,7 @@ |
1415 | QVariantDictMap get_restore_choices_var_dict_map(QDBusConnection bus, |
1416 | QDBusMessage const & msg) |
1417 | { |
1418 | + cached_restore_choices_.clear(); |
1419 | connections_.connect_oneshot( |
1420 | this, |
1421 | &KeeperPrivate::restore_choices_ready, |
1422 | @@ -306,6 +310,13 @@ |
1423 | |
1424 | private: |
1425 | |
1426 | + void on_task_manager_finished() |
1427 | + { |
1428 | + // force a backup choices regeneration to avoid repeating uuids |
1429 | + // between backups |
1430 | + invalidate_choices_cache(); |
1431 | + } |
1432 | + |
1433 | void check_for_unhandled_tasks(QSet<QString> const & unhandled, |
1434 | QDBusConnection bus, |
1435 | QDBusMessage const & msg ) |
1436 | |
1437 | === modified file 'src/service/main.cpp' |
1438 | --- src/service/main.cpp 2016-08-10 05:41:26 +0000 |
1439 | +++ src/service/main.cpp 2016-12-16 09:34:32 +0000 |
1440 | @@ -20,6 +20,7 @@ |
1441 | |
1442 | #include "dbus-types.h" |
1443 | #include "helper/data-dir-registry.h" |
1444 | +#include "helper/helper.h" |
1445 | #include "service/backup-choices.h" |
1446 | #include "service/restore-choices.h" |
1447 | #include "service/keeper.h" |
1448 | @@ -45,7 +46,7 @@ |
1449 | |
1450 | QCoreApplication app(argc, argv); |
1451 | DBusTypes::registerMetaTypes(); |
1452 | -// Variant::registerMetaTypes(); |
1453 | + Helper::registerMetaTypes(); |
1454 | std::srand(unsigned(std::time(nullptr))); |
1455 | |
1456 | util::UnixSignalHandler handler([]{ |
1457 | |
1458 | === modified file 'src/service/task-manager.cpp' |
1459 | --- src/service/task-manager.cpp 2016-11-21 11:09:07 +0000 |
1460 | +++ src/service/task-manager.cpp 2016-12-16 09:34:32 +0000 |
1461 | @@ -111,6 +111,7 @@ |
1462 | // notify the initial state once for all tasks |
1463 | notify_state_changed(); |
1464 | remaining_tasks_.clear(); |
1465 | + Q_EMIT(q_ptr->finished()); |
1466 | } |
1467 | |
1468 | private: |
1469 | @@ -172,17 +173,18 @@ |
1470 | set_current_task_action(task_->to_string(Helper::State::FAILED)); |
1471 | } |
1472 | active_manifest_.reset(); |
1473 | + |
1474 | + Q_EMIT(q_ptr->finished()); |
1475 | } |
1476 | |
1477 | void on_helper_state_changed(Helper::State state) |
1478 | { |
1479 | auto backup_task_ = qSharedPointerDynamicCast<KeeperTaskBackup>(task_); |
1480 | auto& td = task_data_[current_task_]; |
1481 | - update_task_state(td); |
1482 | |
1483 | // for the last completed backup task we delay updating the |
1484 | // state until the manifest file is stored |
1485 | - if (remaining_tasks_.size() || state != Helper::State::COMPLETE) |
1486 | + if (remaining_tasks_.size() || (state != Helper::State::COMPLETE && state != Helper::State::FAILED)) |
1487 | update_task_state(td); |
1488 | |
1489 | if (state == Helper::State::COMPLETE || state == Helper::State::FAILED) |
1490 | @@ -213,6 +215,10 @@ |
1491 | ); |
1492 | active_manifest_->store(); |
1493 | } |
1494 | + else |
1495 | + { |
1496 | + update_task_state(td); |
1497 | + } |
1498 | } |
1499 | } |
1500 | } |
1501 | |
1502 | === modified file 'src/service/task-manager.h' |
1503 | --- src/service/task-manager.h 2016-11-21 11:09:07 +0000 |
1504 | +++ src/service/task-manager.h 2016-12-16 09:34:32 +0000 |
1505 | @@ -65,6 +65,7 @@ |
1506 | Q_SIGNALS: |
1507 | void socket_ready(int reply); |
1508 | void state_changed(); |
1509 | + void finished(); |
1510 | |
1511 | private: |
1512 | QScopedPointer<TaskManagerPrivate> const d_ptr; |
1513 | |
1514 | === modified file 'src/storage-framework/storage_framework_client.cpp' |
1515 | --- src/storage-framework/storage_framework_client.cpp 2016-11-24 14:48:35 +0000 |
1516 | +++ src/storage-framework/storage_framework_client.cpp 2016-12-16 09:34:32 +0000 |
1517 | @@ -168,7 +168,7 @@ |
1518 | connection_helper_.connect_future( |
1519 | get_keeper_folder(root, dir_name, false), |
1520 | std::function<void(sf::Folder::SPtr const&)>{ |
1521 | - [this, fi, file_name](sf::Folder::SPtr const& keeper_root){ |
1522 | + [this, fi, file_name, root](sf::Folder::SPtr const& keeper_root){ |
1523 | if (!keeper_root) |
1524 | { |
1525 | qWarning() << "Error accessing keeper root folder"; |
1526 | @@ -183,12 +183,12 @@ |
1527 | connection_helper_.connect_future( |
1528 | get_storage_framework_file(keeper_root, file_name), |
1529 | std::function<void(sf::File::SPtr const&)>{ |
1530 | - [this, fi](sf::File::SPtr const& sf_file){ |
1531 | + [this, fi, root, keeper_root](sf::File::SPtr const& sf_file){ |
1532 | if (sf_file) { |
1533 | connection_helper_.connect_future( |
1534 | sf_file->create_downloader(), |
1535 | std::function<void(sf::Downloader::SPtr const&)>{ |
1536 | - [this, fi, sf_file](sf::Downloader::SPtr const& sf_downloader){ |
1537 | + [this, fi, sf_file, keeper_root, root](sf::Downloader::SPtr const& sf_downloader){ |
1538 | std::shared_ptr<Downloader> ret; |
1539 | if (sf_downloader) |
1540 | { |
1541 | |
1542 | === modified file 'tests/unit/helper/CMakeLists.txt' |
1543 | --- tests/unit/helper/CMakeLists.txt 2016-09-27 11:22:15 +0000 |
1544 | +++ tests/unit/helper/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
1545 | @@ -28,6 +28,7 @@ |
1546 | target_link_libraries( |
1547 | ${SPEED_TEST} |
1548 | ${UNIT_TEST_LIBRARIES} |
1549 | + storage-framework |
1550 | Qt5::Core |
1551 | Qt5::DBus |
1552 | Qt5::Test |
1553 | |
1554 | === modified file 'tests/unit/manifest/CMakeLists.txt' |
1555 | --- tests/unit/manifest/CMakeLists.txt 2016-10-06 14:53:44 +0000 |
1556 | +++ tests/unit/manifest/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
1557 | @@ -27,6 +27,7 @@ |
1558 | target_link_libraries( |
1559 | ${MANIFEST_TEST} |
1560 | ${UNIT_TEST_LIBRARIES} |
1561 | + backup-helper |
1562 | Qt5::Core |
1563 | Qt5::DBus |
1564 | Qt5::Test |
1565 | |
1566 | === modified file 'tests/unit/metadata-providers/CMakeLists.txt' |
1567 | --- tests/unit/metadata-providers/CMakeLists.txt 2016-07-31 17:20:13 +0000 |
1568 | +++ tests/unit/metadata-providers/CMakeLists.txt 2016-12-16 09:34:32 +0000 |
1569 | @@ -11,6 +11,9 @@ |
1570 | target_link_libraries( |
1571 | ${TEST_NAME} |
1572 | ${UNIT_TEST_LIBRARIES} |
1573 | + storage-framework |
1574 | + backup-helper |
1575 | + ${SERVICE_DEVEL_SF_DEPS_LIBRARIES} |
1576 | Qt5::Core |
1577 | Qt5::DBus |
1578 | Qt5::Test |
FAILED: Continuous integration, rev:146 /jenkins. canonical. com/unity- api-1/job/ lp-keeper- ci/145/ /jenkins. canonical. com/unity- api-1/job/ build/1220/ console /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/1227/ console
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-keeper- ci/145/ rebuild
https:/