Merge lp:~diegosarmentero/ubuntuone-client/ubuntuone-client-syncc into lp:ubuntuone-client

Proposed by Diego Sarmentero
Status: Merged
Approved by: Diego Sarmentero
Approved revision: 1360
Merged at revision: 1316
Proposed branch: lp:~diegosarmentero/ubuntuone-client/ubuntuone-client-syncc
Merge into: lp:ubuntuone-client
Diff against target: 768 lines (+686/-2)
8 files modified
po/POTFILES.in (+1/-0)
tests/platform/sync_menu/__init__.py (+27/-0)
tests/platform/sync_menu/test_linux.py (+316/-0)
tests/syncdaemon/test_main.py (+14/-0)
ubuntuone/platform/sync_menu/__init__.py (+41/-0)
ubuntuone/platform/sync_menu/common.py (+43/-0)
ubuntuone/platform/sync_menu/linux.py (+230/-0)
ubuntuone/syncdaemon/main.py (+14/-2)
To merge this branch: bzr merge lp:~diegosarmentero/ubuntuone-client/ubuntuone-client-syncc
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Approve
Roberto Alsina (community) Approve
Review via email: mp+124968@code.launchpad.net

Commit message

- Adding SyncMenu to u1-client (LP: #1042343).

To post a comment you must log in.
Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

You can test this branch in Q like this:

sudo apt-get build-dep indicator-sync
bzr branch lp:indicator-sync
cd indicator-sync
./autogen.sh; make

check out the README file inside the example folder, and follow those instructions, but instead executing the C example, run u1-client from this branch.

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

It's necessary also to install:
sudo apt-get install gir1.2-syncmenu-0.1

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :
Revision history for this message
Roberto Alsina (ralsina) wrote :

Looks good to me. Could not run it because Q is not cooperating today.

review: Approve
Revision history for this message
Alejandro J. Cura (alecu) wrote :

The code on this branch looks fine, but testing this branch IRL shows a very noticeable regression:
Syndaemon running from trunk uses 0% cpu while idle. This branch uses 1% cpu on my machine (+1% cpu for the sync indicator processes), due to the constant updating of the menu.

I think we should both reduce the time between updates for this branch, and create a new bug, and try to come up with a less resource intensive approach, like having the status aggregator code calling some callback in this module whenever there's transfer progress (and even so, no more often than every two or three seconds).

---

Small issue: all occurrences similar to:

213 + def fake_open(url):
214 + data.append(url)
215 +
216 + self.patch(linux.webbrowser, "open", fake_open)

Can be replaced with just this line:

213 + self.patch(linux.webbrowser, "open", data.append)

review: Needs Information
Revision history for this message
Alejandro J. Cura (alecu) wrote :

After discussing on IRC, we decided to land this branch as is and work on a fix for the cpu issue in a different branch.

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (28.2 KiB)

The attempt to merge lp:~diegosarmentero/ubuntuone-client/ubuntuone-client-syncc into lp:ubuntuone-client failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
  testing autoconf2.50... not found.
  testing autoconf... found 2.69
checking for automake >= 1.10...
  testing automake-1.12... not found.
  testing automake-1.11... found 1.11.5
checking for libtool >= 1.5...
  testing libtoolize... found 2.4.2
checking for intltool >= 0.30...
  testing intltoolize... found 0.50.2
checking for pkg-config >= 0.14.0...
  testing pkg-config... found 0.26
checking for gtk-doc >= 1.0...
  testing gtkdocize... found 1.18
Checking for required M4 macros...
Checking for forbidden M4 macros...
Processing ./configure.ac
Running libtoolize...
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
Running gtkdocize...
Running aclocal-1.11...
Running autoconf...
Running autoheader...
Running automake-1.11...
Running ./configure --enable-gtk-doc --enable-debug ...
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking how to create a ustar tar archive... gnutar
checking whether make supports nested variables... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking how to print strings... printf
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whe...

1360. By Diego Sarmentero

Making the syncmenu integration not be required on linux

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2011-08-16 13:44:20 +0000
+++ po/POTFILES.in 2012-09-19 17:25:32 +0000
@@ -1,6 +1,7 @@
1ubuntuone/clientdefs.py.in1ubuntuone/clientdefs.py.in
2ubuntuone/status/aggregator.py2ubuntuone/status/aggregator.py
3ubuntuone/platform/credentials/__init__.py3ubuntuone/platform/credentials/__init__.py
4ubuntuone/platform/sync_menu/linux.py
4data/emblem-ubuntuone-downloading.icon.in5data/emblem-ubuntuone-downloading.icon.in
5data/emblem-ubuntuone-unsynchronized.icon.in6data/emblem-ubuntuone-unsynchronized.icon.in
6data/emblem-ubuntuone-uploading.icon.in7data/emblem-ubuntuone-uploading.icon.in
78
=== added directory 'tests/platform/sync_menu'
=== added file 'tests/platform/sync_menu/__init__.py'
--- tests/platform/sync_menu/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/platform/sync_menu/__init__.py 2012-09-19 17:25:32 +0000
@@ -0,0 +1,27 @@
1# Copyright 2012 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14#
15# In addition, as a special exception, the copyright holders give
16# permission to link the code of portions of this program with the
17# OpenSSL library under certain conditions as described in each
18# individual source file, and distribute linked combinations
19# including the two.
20# You must obey the GNU General Public License in all respects
21# for all of the code used other than OpenSSL. If you modify
22# file(s) with this exception, you may extend this exception to your
23# version of the file(s), but you are not obligated to do so. If you
24# do not wish to do so, delete this exception statement from your
25# version. If you delete this exception statement from all source
26# files in the program, then also delete it here.
27"""SyncMenu test code."""
028
=== added file 'tests/platform/sync_menu/test_linux.py'
--- tests/platform/sync_menu/test_linux.py 1970-01-01 00:00:00 +0000
+++ tests/platform/sync_menu/test_linux.py 2012-09-19 17:25:32 +0000
@@ -0,0 +1,316 @@
1# -*- coding: utf-8 *-*
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Test the Sync Menu."""
30
31from twisted.internet import defer
32from twisted.trial.unittest import TestCase
33
34from ubuntuone.platform import sync_menu
35from ubuntuone.platform.sync_menu import linux
36
37
38def fake_call_later(*args):
39 """Fake reactor.callLater."""
40
41
42class FakeStatusFrontend(object):
43 """Fake StatusFrontend."""
44
45 def __init__(self):
46 self.recent_transfers_data = []
47 self.uploading_data = []
48
49 def recent_transfers(self):
50 """Return the fake recent transfers files."""
51 return self.recent_transfers_data
52
53 def files_uploading(self):
54 """Return the fake files being upload."""
55 return self.uploading_data
56
57
58class FakeStatusListener(object):
59 """Fake StatusListener."""
60
61 def __init__(self):
62 self.status_frontend = FakeStatusFrontend()
63
64
65class FakeMain(object):
66 """Fake Main."""
67
68 def __init__(self):
69 self.status_listener = FakeStatusListener()
70
71
72class FakeSyncMenuApp(object):
73 """Fake SyncMenu."""
74
75 data = {}
76
77 @classmethod
78 def new(cls, *args):
79 return FakeSyncMenuApp()
80
81 @classmethod
82 def clean(cls):
83 """Clear the values stored in data."""
84
85 def set_menu(self, server):
86 """Set the menu for SyncMenu App."""
87 self.data['server'] = server
88
89 def connect(self, signal, callback):
90 """Fake connect."""
91 self.data['connect'] = (signal, callback)
92
93
94class SyncMenuTestCase(TestCase):
95 """Test the SyncMenu."""
96
97 skip = None if linux.use_syncmenu else "SyncMenu not installed."
98
99 @defer.inlineCallbacks
100 def setUp(self):
101 yield super(SyncMenuTestCase, self).setUp()
102 self.patch(linux.SyncMenu, "App", FakeSyncMenuApp)
103 FakeSyncMenuApp.clean()
104 self.main = FakeMain()
105 self.status_frontend = self.main.status_listener.status_frontend
106 self._paused = False
107 self.patch(sync_menu.UbuntuOneSyncMenu, "change_sync_status",
108 self._change_sync_status)
109 self.sync_menu = sync_menu.UbuntuOneSyncMenu(self.main)
110
111 def _change_sync_status(self, *args):
112 """Fake change_sync_status."""
113 if self._paused:
114 self._paused = False
115 else:
116 self._paused = True
117
118 def test_init(self):
119 """Check that the menu is properly initialized."""
120 self.assertIsInstance(FakeSyncMenuApp.data['server'],
121 linux.Dbusmenu.Server)
122 self.assertEqual(self.sync_menu.open_u1.get_parent(),
123 self.sync_menu.root_menu)
124 self.assertEqual(self.sync_menu.go_to_web.get_parent(),
125 self.sync_menu.root_menu)
126 self.assertEqual(self.sync_menu.more_storage.get_parent(),
127 self.sync_menu.root_menu)
128 self.assertEqual(self.sync_menu.get_help.get_parent(),
129 self.sync_menu.root_menu)
130 self.assertEqual(self.sync_menu.transfers.get_parent(),
131 self.sync_menu.root_menu)
132
133 self.assertEqual(self.sync_menu.open_u1.property_get(
134 linux.Dbusmenu.MENUITEM_PROP_LABEL), linux.OPEN_U1)
135 self.assertEqual(self.sync_menu.go_to_web.property_get(
136 linux.Dbusmenu.MENUITEM_PROP_LABEL), linux.GO_TO_WEB)
137 self.assertEqual(self.sync_menu.transfers.property_get(
138 linux.Dbusmenu.MENUITEM_PROP_LABEL), linux.TRANSFERS)
139 self.assertEqual(self.sync_menu.more_storage.property_get(
140 linux.Dbusmenu.MENUITEM_PROP_LABEL), linux.MORE_STORAGE)
141 self.assertEqual(self.sync_menu.get_help.property_get(
142 linux.Dbusmenu.MENUITEM_PROP_LABEL), linux.GET_HELP)
143
144 self.assertEqual(self.sync_menu.app.data['connect'],
145 ("notify::paused", self.sync_menu.change_sync_status))
146 self.sync_menu.app.data['connect'][1]()
147 self.assertTrue(self._paused)
148 self.sync_menu.app.data['connect'][1]()
149 self.assertFalse(self._paused)
150
151 def test_open_u1(self):
152 """Check that the proper action is executed."""
153 data = []
154
155 self.patch(linux.glib, "spawn_command_line_async", data.append)
156 self.sync_menu.open_control_panel()
157 self.assertEqual(data, ['ubuntuone-installer'])
158
159 def test_go_to_web(self):
160 """Check that the proper action is executed."""
161 data = []
162
163 self.patch(linux.webbrowser, "open", data.append)
164 self.sync_menu.open_go_to_web()
165 self.assertEqual(data, [linux.DASHBOARD])
166
167 def test_get_help(self):
168 """Check that the proper action is executed."""
169 data = []
170
171 self.patch(linux.webbrowser, "open", data.append)
172 self.sync_menu.open_web_help()
173 self.assertEqual(data, [linux.HELP_LINK])
174
175 def test_more_storage(self):
176 """Check that the proper action is executed."""
177 data = []
178
179 self.patch(linux.webbrowser, "open", data.append)
180 self.sync_menu.open_get_more_storage()
181 self.assertEqual(data, [linux.GET_STORAGE_LINK])
182
183 def test_empty_transfers(self):
184 """Check that the Transfers menu is empty."""
185 self.assertEqual(self.sync_menu.transfers.get_children(), [])
186
187 def test_only_recent(self):
188 """Check that only recent transfers items are loaded."""
189 data = ['file1', 'file2', 'file3']
190 self.status_frontend.recent_transfers_data = data
191 self.sync_menu.transfers.update_progress()
192 children = self.sync_menu.transfers.get_children()
193 self.assertEqual(len(children), 3)
194 data.reverse()
195 for itemM, itemD in zip(children, data):
196 self.assertEqual(itemM.property_get(
197 linux.Dbusmenu.MENUITEM_PROP_LABEL), itemD)
198
199 def test_only_progress(self):
200 """Check that only progress items are loaded."""
201 data = [
202 ('file1', 3000, 400),
203 ('file2', 2000, 100),
204 ('file3', 5000, 4600)]
205 uploading_data = {}
206 for filename, size, written in data:
207 uploading_data[filename] = (size, written)
208 self.status_frontend.uploading_data = data
209 self.sync_menu.transfers.update_progress()
210 children = self.sync_menu.transfers.get_children()
211 self.assertEqual(len(children), 3)
212 data.reverse()
213 for item in children:
214 text = item.property_get(linux.Dbusmenu.MENUITEM_PROP_LABEL)
215 self.assertIn(text, uploading_data)
216 size, written = uploading_data[text]
217 percentage = written * 100 / size
218 self.assertEqual(item.property_get_int(
219 linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE),
220 percentage)
221
222 def test_full_transfers(self):
223 """Check that the transfers menu contains the maximum transfers."""
224 # The api of recent transfers always returns a maximum of 5 items
225 data_recent = ['file1', 'file2', 'file3', 'file4', 'file5']
226 self.status_frontend.recent_transfers_data = \
227 data_recent
228 self.sync_menu.transfers.update_progress()
229 children = self.sync_menu.transfers.get_children()
230 self.assertEqual(len(children), 5)
231 data_recent.reverse()
232 for itemM, itemD in zip(children, data_recent):
233 self.assertEqual(itemM.property_get(
234 linux.Dbusmenu.MENUITEM_PROP_LABEL), itemD)
235
236 data_current = [
237 ('file0', 1200, 600),
238 ('file1', 3000, 400),
239 ('file2', 2000, 100),
240 ('file3', 2500, 150),
241 ('file4', 1000, 600),
242 ('file5', 5000, 4600)]
243 uploading_data = {}
244 for filename, size, written in data_current:
245 uploading_data[filename] = (size, written)
246 self.status_frontend.uploading_data = data_current
247 self.sync_menu.transfers.update_progress()
248 children = self.sync_menu.transfers.get_children()
249 # The menu should only show 5 current transfers.
250 self.assertEqual(len(children), 10)
251 data_current.reverse()
252 for item in children[5:]:
253 text = item.property_get(linux.Dbusmenu.MENUITEM_PROP_LABEL)
254 self.assertIn(text, uploading_data)
255 size, written = uploading_data[text]
256 percentage = written * 100 / size
257 self.assertEqual(item.property_get_int(
258 linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE),
259 percentage)
260
261 def test_update_transfers(self):
262 """Check that everything is ok when updating the transfers value."""
263 data_current = [
264 ('file0', 1200, 600),
265 ('file1', 3000, 400),
266 ('file4', 1000, 600),
267 ('file5', 5000, 4600)]
268 uploading_data = {}
269 for filename, size, written in data_current:
270 uploading_data[filename] = (size, written)
271 self.status_frontend.uploading_data = data_current
272 self.sync_menu.transfers.update_progress()
273 children = self.sync_menu.transfers.get_children()
274 # The menu should only show 5 current transfers.
275 self.assertEqual(len(children), 4)
276 data_current.reverse()
277 for item in children:
278 text = item.property_get(linux.Dbusmenu.MENUITEM_PROP_LABEL)
279 self.assertIn(text, uploading_data)
280 size, written = uploading_data[text]
281 percentage = written * 100 / size
282 self.assertEqual(item.property_get_int(
283 linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE),
284 percentage)
285
286 data_recent = ['file5']
287 self.status_frontend.recent_transfers_data = data_recent
288 self.sync_menu.transfers.update_progress()
289 children = self.sync_menu.transfers.get_children()
290 self.assertEqual(len(children), 5)
291 data_recent.reverse()
292 for itemM, itemD in zip(children, data_recent):
293 self.assertEqual(itemM.property_get(
294 linux.Dbusmenu.MENUITEM_PROP_LABEL), itemD)
295
296 data_current = [
297 ('file0', 1200, 700),
298 ('file1', 3000, 600),
299 ('file4', 1000, 800)]
300 uploading_data = {}
301 for filename, size, written in data_current:
302 uploading_data[filename] = (size, written)
303 self.status_frontend.uploading_data = data_current
304 self.sync_menu.transfers.update_progress()
305 children = self.sync_menu.transfers.get_children()
306 # The menu should only show 5 current transfers.
307 self.assertEqual(len(children), 4)
308 data_current.reverse()
309 for item in children[5:]:
310 text = item.property_get(linux.Dbusmenu.MENUITEM_PROP_LABEL)
311 self.assertIn(text, uploading_data)
312 size, written = uploading_data[text]
313 percentage = written * 100 / size
314 self.assertEqual(item.property_get_int(
315 linux.SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE),
316 percentage)
0317
=== modified file 'tests/syncdaemon/test_main.py'
--- tests/syncdaemon/test_main.py 2012-06-21 18:58:50 +0000
+++ tests/syncdaemon/test_main.py 2012-09-19 17:25:32 +0000
@@ -70,6 +70,19 @@
70 return defer.succeed(None)70 return defer.succeed(None)
7171
7272
73class FakedSyncMenu(object):
74 """Do nothing."""
75
76 def __init__(self, *args, **kwargs):
77 self.arguments = (args, kwargs)
78
79 def update_progress(self):
80 """Do nothing."""
81
82 def start_timer(self):
83 """Do nothing."""
84
85
73class MainTests(BaseTwistedTestCase):86class MainTests(BaseTwistedTestCase):
74 """ Basic tests to check main.Main """87 """ Basic tests to check main.Main """
7588
@@ -87,6 +100,7 @@
87 self.patch(main_mod.event_logging, "get_listener", lambda *a: None)100 self.patch(main_mod.event_logging, "get_listener", lambda *a: None)
88 # no status listener by default101 # no status listener by default
89 self.patch(main_mod.status_listener, "get_listener", lambda *a: None)102 self.patch(main_mod.status_listener, "get_listener", lambda *a: None)
103 self.patch(main_mod.sync_menu, "UbuntuOneSyncMenu", FakedSyncMenu)
90104
91 self.handler = MementoHandler()105 self.handler = MementoHandler()
92 self.handler.setLevel(logging.DEBUG)106 self.handler.setLevel(logging.DEBUG)
93107
=== added directory 'ubuntuone/platform/sync_menu'
=== added file 'ubuntuone/platform/sync_menu/__init__.py'
--- ubuntuone/platform/sync_menu/__init__.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/platform/sync_menu/__init__.py 2012-09-19 17:25:32 +0000
@@ -0,0 +1,41 @@
1# -*- coding: utf-8 *-*
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Use SyncMenu lib to integrate U1 with the Systray Sync Icon."""
30
31import sys
32
33
34if sys.platform in ("win32", "darwin"):
35 from ubuntuone.platform.sync_menu import common
36 source = common
37else:
38 from ubuntuone.platform.sync_menu import linux
39 source = linux
40
41UbuntuOneSyncMenu = source.UbuntuOneSyncMenu
042
=== added file 'ubuntuone/platform/sync_menu/common.py'
--- ubuntuone/platform/sync_menu/common.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/platform/sync_menu/common.py 2012-09-19 17:25:32 +0000
@@ -0,0 +1,43 @@
1# -*- coding: utf-8 *-*
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Use SyncMenu lib to integrate U1 with the Systray Sync Icon."""
30
31
32class UbuntuOneSyncMenu(object):
33 """Integrate U1 with the Ubuntu Sync Menu."""
34
35 def __init__(self, *args):
36 self.transfers = DummyTransfersMenu()
37
38
39class DummyTransfersMenu(object):
40 """Dummy Transfers Menu."""
41
42 def start_timer(self):
43 """Empty start timer, this is not needed on windows."""
044
=== added file 'ubuntuone/platform/sync_menu/linux.py'
--- ubuntuone/platform/sync_menu/linux.py 1970-01-01 00:00:00 +0000
+++ ubuntuone/platform/sync_menu/linux.py 2012-09-19 17:25:32 +0000
@@ -0,0 +1,230 @@
1# -*- coding: utf-8 *-*
2#
3# Copyright 2012 Canonical Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# In addition, as a special exception, the copyright holders give
18# permission to link the code of portions of this program with the
19# OpenSSL library under certain conditions as described in each
20# individual source file, and distribute linked combinations
21# including the two.
22# You must obey the GNU General Public License in all respects
23# for all of the code used other than OpenSSL. If you modify
24# file(s) with this exception, you may extend this exception to your
25# version of the file(s), but you are not obligated to do so. If you
26# do not wish to do so, delete this exception statement from your
27# version. If you delete this exception statement from all source
28# files in the program, then also delete it here.
29"""Use SyncMenu lib to integrate U1 with the Systray Sync Icon."""
30
31import gettext
32import sys
33import webbrowser
34
35glib = None
36try:
37 if 'gobject' in sys.modules and sys.modules['gobject'] is not None:
38 import glib as GLib
39 glib = GLib
40 else:
41 from gi.repository import GLib
42 glib = GLib
43except ImportError:
44 pass
45try:
46 from gi.repository import (
47 Dbusmenu,
48 SyncMenu,
49 )
50 use_syncmenu = True
51except:
52 use_syncmenu = False
53from twisted.internet import reactor
54
55from ubuntuone.clientdefs import GETTEXT_PACKAGE
56
57
58Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string)
59
60OPEN_U1 = Q_("Open Ubuntu One")
61GO_TO_WEB = Q_("Go to the Ubuntu One Website")
62TRANSFERS = Q_("Current and Recent Transfers")
63MORE_STORAGE = Q_("Get More Space")
64GET_HELP = Q_("Get Help on the Web")
65
66UBUNTUONE_LINK = u'https://one.ubuntu.com/'
67DASHBOARD = UBUNTUONE_LINK + u'dashboard/'
68HELP_LINK = UBUNTUONE_LINK + u'support/'
69GET_STORAGE_LINK = UBUNTUONE_LINK + u'services/#storage_panel'
70
71
72class UbuntuOneSyncMenuLinux(object):
73 """Integrate U1 with the Ubuntu Sync Menu."""
74
75 def __init__(self, main):
76 """Initialize menu."""
77 self._main = main
78 self.status_listener = main.status_listener
79 self._paused = False
80 self.root_menu = Dbusmenu.Menuitem()
81
82 self.open_u1 = Dbusmenu.Menuitem()
83 self.open_u1.property_set(Dbusmenu.MENUITEM_PROP_LABEL, OPEN_U1)
84
85 self.go_to_web = Dbusmenu.Menuitem()
86 self.go_to_web.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
87 GO_TO_WEB)
88
89 self.transfers = TransfersMenu(self.status_listener)
90 self.transfers.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
91 TRANSFERS)
92
93 self.more_storage = Dbusmenu.Menuitem()
94 self.more_storage.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
95 MORE_STORAGE)
96
97 self.get_help = Dbusmenu.Menuitem()
98 self.get_help.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
99 GET_HELP)
100
101 # Connect signals
102 self.open_u1.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED,
103 self.open_control_panel)
104 self.go_to_web.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED,
105 self.open_go_to_web)
106 self.get_help.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED,
107 self.open_web_help)
108 self.more_storage.connect(Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED,
109 self.open_get_more_storage)
110
111 # Add items
112 self.root_menu.child_append(self.open_u1)
113 self.root_menu.child_append(self.go_to_web)
114 self.root_menu.child_append(self.transfers)
115 self.root_menu.child_append(self.more_storage)
116 self.root_menu.child_append(self.get_help)
117
118 self.server = Dbusmenu.Server()
119 self.server.set_root(self.root_menu)
120 self.app = SyncMenu.App.new("ubuntuone-installer.desktop")
121 self.app.set_menu(self.server)
122 self.app.connect("notify::paused", self.change_sync_status)
123
124 def start_timer(self):
125 """Start the transfers timer."""
126 self.transfers.start_timer()
127
128 def change_sync_status(self, *args):
129 """Triggered when the sync status is changed fromm the menu."""
130 if self._paused:
131 self._main.external.connect()
132 self._paused = False
133 else:
134 self._main.external.disconnect()
135 self._paused = True
136
137 def open_control_panel(self, *args):
138 """Open the Ubuntu One Control Panel."""
139 glib.spawn_command_line_async('ubuntuone-installer')
140
141 def open_go_to_web(self, *args):
142 """Open the Ubunto One Help Page"""
143 webbrowser.open(DASHBOARD)
144
145 def open_web_help(self, *args):
146 """Open the Ubunto One Help Page"""
147 webbrowser.open(HELP_LINK)
148
149 def open_get_more_storage(self, *args):
150 """Open the Ubunto One Help Page"""
151 webbrowser.open(GET_STORAGE_LINK)
152
153
154class TransfersMenu(Dbusmenu.Menuitem):
155 """Menu that handles the recent and current transfers."""
156
157 def __init__(self, listener):
158 super(TransfersMenu, self).__init__()
159 self.listener = listener
160 self.uploading = {}
161 self.previous_transfers = []
162 self._transfers_items = {}
163 self._uploading_items = {}
164
165 def start_timer(self):
166 """Trigger an update in one second."""
167 self.update_progress()
168 reactor.callLater(3, self.start_timer)
169
170 def update_progress(self):
171 """Update the list of recent transfers and current transfers."""
172 current_transfers = self.listener.status_frontend.recent_transfers()
173 uploading_data = {}
174 for filename, size, written in \
175 self.listener.status_frontend.files_uploading():
176 uploading_data[filename] = (size, written)
177
178 temp_transfers = {}
179 if current_transfers != self.previous_transfers:
180 for item_transfer in self._transfers_items:
181 self.child_delete(self._transfers_items[item_transfer])
182 for item in current_transfers:
183 recent_file = Dbusmenu.Menuitem()
184 recent_file.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
185 item)
186 self.child_add_position(recent_file, 0)
187 temp_transfers[item] = recent_file
188 self._transfers_items = temp_transfers
189
190 items_added = 0
191 remove = []
192 for item in self._uploading_items:
193 if item in uploading_data:
194 size, written = uploading_data[item]
195 percentage = written * 100 / size
196 upload_item = self._uploading_items[item]
197 upload_item.property_set_int(
198 SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE,
199 percentage)
200 items_added += 1
201 else:
202 self.child_delete(self._uploading_items[item])
203 remove.append(item)
204 for item in remove:
205 self._uploading_items.pop(item)
206 if items_added < 5:
207 for item in uploading_data:
208 if item not in self._uploading_items and items_added < 5:
209 size, written = uploading_data[item]
210 percentage = written * 100 / size
211 uploading_file = Dbusmenu.Menuitem()
212 uploading_file.property_set(Dbusmenu.MENUITEM_PROP_LABEL,
213 item)
214 uploading_file.property_set(Dbusmenu.MENUITEM_PROP_TYPE,
215 SyncMenu.PROGRESS_MENUITEM_TYPE)
216 uploading_file.property_set_int(
217 SyncMenu.PROGRESS_MENUITEM_PROP_PERCENT_DONE,
218 percentage)
219 self.child_append(uploading_file)
220 self._uploading_items[item] = uploading_file
221 items_added += 1
222
223
224class DummySyncMenu(object):
225
226 def start_timer(self):
227 """Do nothing."""
228
229
230UbuntuOneSyncMenu = UbuntuOneSyncMenuLinux if use_syncmenu else DummySyncMenu
0231
=== modified file 'ubuntuone/syncdaemon/main.py'
--- ubuntuone/syncdaemon/main.py 2012-07-12 16:04:44 +0000
+++ ubuntuone/syncdaemon/main.py 2012-09-19 17:25:32 +0000
@@ -48,7 +48,10 @@
48 volume_manager,48 volume_manager,
49)49)
50from ubuntuone import syncdaemon, clientdefs50from ubuntuone import syncdaemon, clientdefs
51from ubuntuone.platform import event_logging51from ubuntuone.platform import (
52 event_logging,
53 sync_menu,
54)
52from ubuntuone.syncdaemon import status_listener55from ubuntuone.syncdaemon import status_listener
53from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService56from ubuntuone.syncdaemon.interaction_interfaces import SyncdaemonService
54from ubuntuone.syncdaemon.states import StateManager, QueueManager57from ubuntuone.syncdaemon.states import StateManager, QueueManager
@@ -90,7 +93,8 @@
90 handshake_timeout=30,93 handshake_timeout=30,
91 shares_symlink_name='Shared With Me',94 shares_symlink_name='Shared With Me',
92 read_limit=None, write_limit=None, throttling_enabled=False,95 read_limit=None, write_limit=None, throttling_enabled=False,
93 ignore_files=None, oauth_credentials=None, monitor_class=None):96 ignore_files=None, oauth_credentials=None,
97 monitor_class=None):
94 self.root_dir = root_dir98 self.root_dir = root_dir
95 self.shares_dir = shares_dir99 self.shares_dir = shares_dir
96 self.shares_dir_link = os.path.join(self.root_dir, shares_symlink_name)100 self.shares_dir_link = os.path.join(self.root_dir, shares_symlink_name)
@@ -155,6 +159,14 @@
155 self.mark = task.LoopingCall(self.log_mark)159 self.mark = task.LoopingCall(self.log_mark)
156 self.mark.start(mark_interval)160 self.mark.start(mark_interval)
157161
162 self.sync_menu = None
163 self.start_sync_menu()
164
165 def start_sync_menu(self):
166 """Create the sync menu and run the loop."""
167 self.sync_menu = sync_menu.UbuntuOneSyncMenu(self)
168 self.sync_menu.start_timer()
169
158 def start_event_logger(self):170 def start_event_logger(self):
159 """Start the event logger if it's available for this platform."""171 """Start the event logger if it's available for this platform."""
160 self.eventlog_listener = event_logging.get_listener(self.fs, self.vm)172 self.eventlog_listener = event_logging.get_listener(self.fs, self.vm)

Subscribers

People subscribed via source and target branches