Merge lp:~ralsina/ubuntu-sso-client/log-better into lp:ubuntu-sso-client

Proposed by Roberto Alsina
Status: Merged
Approved by: Natalia Bidart
Approved revision: 772
Merged at revision: 764
Proposed branch: lp:~ralsina/ubuntu-sso-client/log-better
Merge into: lp:ubuntu-sso-client
Diff against target: 413 lines (+347/-5)
7 files modified
ubuntu_sso/logger.py (+2/-3)
ubuntu_sso/utils/ui.py (+2/-2)
ubuntu_sso/xdg_base_directory/__init__.py (+40/-0)
ubuntu_sso/xdg_base_directory/tests/__init__.py (+16/-0)
ubuntu_sso/xdg_base_directory/tests/test_common.py (+56/-0)
ubuntu_sso/xdg_base_directory/tests/test_windows.py (+112/-0)
ubuntu_sso/xdg_base_directory/windows.py (+119/-0)
To merge this branch: bzr merge lp:~ralsina/ubuntu-sso-client/log-better
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Review via email: mp+72573@code.launchpad.net

Commit message

Move the windows xdg implementation from u1-client to sso so we can use it in all our projects.

Description of the change

Move the windows xdg implementation from u1-client to sso so we can use it in all our projects.

To post a comment you must log in.
767. By Roberto Alsina

added the windows-specific tests

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

So, since we're adding a new multiplatform module, we need to come up with something like this:

ubuntu_sso/
    main/
    foo/
    xdg_base_directory/
        __init__.py
        windows.py
        tests/
            __init__.py
            test_common.py <- multiplatform tests
            test_windows.py

review: Needs Fixing
768. By Roberto Alsina

add __init__

769. By Roberto Alsina

forgot one

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

I'm getting all these failures when running ./run-tests:

ubuntu_sso/utils/ui.py:
    121: [E1101, get_data_dir] Module 'ubuntu_sso.xdg_base_directory' has no 'xdg_data_dirs' member

ubuntu_sso/xdg_base_directory/__init__.py:
    24: [C0103] Invalid name "load_config_paths" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    25: [C0103] Invalid name "save_config_path" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    26: [C0103] Invalid name "xdg_cache_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    27: [C0103] Invalid name "xdg_data_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    30: [C0103] Invalid name "load_config_paths" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    31: [C0103] Invalid name "save_config_path" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    32: [C0103] Invalid name "xdg_cache_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    33: [C0103] Invalid name "xdg_data_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    35: [C0103] Invalid name "ubuntuone_log_dir" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)

ubuntu_sso/xdg_base_directory/tests/__init__.py:
    1: [C0111] Missing docstring

ubuntu_sso/xdg_base_directory/windows.py:
    28: [W0621, get_special_folders] Redefining name 'special_folders' from outer scope (line 45)
    23: [C0111, get_special_folders] Missing docstring
    30: [F0401, get_special_folders] Unable to import 'win32com.shell'
    45: [C0103] Invalid name "special_folders" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    47: [C0103] Invalid name "home_path" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    48: [C0103] Invalid name "app_local_data_path" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    49: [C0103] Invalid name "app_global_data_path" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    52: [C0103] Invalid name "xdg_data_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    62: [C0103] Invalid name "xdg_data_dirs" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    66: [C0103] Invalid name "xdg_cache_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    70: [C0103] Invalid name "xdg_config_home" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    81: [C0103] Invalid name "xdg_config_dirs" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    83: [C0103] Invalid name "xdg_data_dirs" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)
    84: [C0103] Invalid name "xdg_config_dirs" (should match (([A-Z_][A-Z0-9_]*)|(__.*__))$)

You may wanna disable C0103 in ubuntu_sso/xdg_base_directory/windows.py and ubuntu_sso/xdg_base_directory/__init__.py.

review: Needs Fixing
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Another style fix:

* this import from logging.handlers import RotatingFileHandler should be separated by a blank line from the stdlib imports.

review: Needs Fixing
770. By Roberto Alsina

style fix

771. By Roberto Alsina

Lint fixes

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

Pushed with all the lint fixes (and hey, it was missing making xdg_data_dirs visible)

772. By Roberto Alsina

publish missing member, lint fixes

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ubuntu_sso/logger.py'
2--- ubuntu_sso/logger.py 2011-01-11 19:13:19 +0000
3+++ ubuntu_sso/logger.py 2011-08-23 15:43:28 +0000
4@@ -25,12 +25,11 @@
5 import os
6 import sys
7
8-import xdg.BaseDirectory
9-
10 from logging.handlers import RotatingFileHandler
11
12+from ubuntu_sso import xdg_base_directory
13
14-LOGFOLDER = os.path.join(xdg.BaseDirectory.xdg_cache_home, 'sso')
15+LOGFOLDER = os.path.join(xdg_base_directory.xdg_cache_home, 'sso')
16 # create log folder if it doesn't exists
17 if not os.path.exists(LOGFOLDER):
18 os.makedirs(LOGFOLDER)
19
20=== modified file 'ubuntu_sso/utils/ui.py'
21--- ubuntu_sso/utils/ui.py 2011-07-28 22:50:33 +0000
22+++ ubuntu_sso/utils/ui.py 2011-08-23 15:43:28 +0000
23@@ -20,10 +20,10 @@
24
25 import os
26 import re
27-import xdg
28 import gettext
29
30 from ubuntu_sso.logger import setup_logging
31+from ubuntu_sso import xdg_base_directory
32
33 logger = setup_logging('ubuntu_sso.utils.ui')
34
35@@ -118,7 +118,7 @@
36 return result
37
38 # no local data dir, looking within system data dirs
39- data_dirs = xdg.BaseDirectory.xdg_data_dirs
40+ data_dirs = xdg_base_directory.xdg_data_dirs
41 for path in data_dirs:
42 result = os.path.join(path, 'ubuntu-sso-client', 'data')
43 result = os.path.abspath(result)
44
45=== added directory 'ubuntu_sso/xdg_base_directory'
46=== added file 'ubuntu_sso/xdg_base_directory/__init__.py'
47--- ubuntu_sso/xdg_base_directory/__init__.py 1970-01-01 00:00:00 +0000
48+++ ubuntu_sso/xdg_base_directory/__init__.py 2011-08-23 15:43:28 +0000
49@@ -0,0 +1,40 @@
50+# Author: Natalia B. Bidart <natalia.bidart@canonical.com>
51+#
52+# Copyright 2011 Canonical Ltd.
53+#
54+# This program is free software: you can redistribute it and/or modify it
55+# under the terms of the GNU General Public License version 3, as published
56+# by the Free Software Foundation.
57+#
58+# This program is distributed in the hope that it will be useful, but
59+# WITHOUT ANY WARRANTY; without even the implied warranties of
60+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
61+# PURPOSE. See the GNU General Public License for more details.
62+#
63+# You should have received a copy of the GNU General Public License along
64+# with this program. If not, see <http://www.gnu.org/licenses/>.
65+
66+"""XDG multiplatform."""
67+
68+import os
69+import sys
70+
71+# pylint: disable=C0103
72+if sys.platform == "win32":
73+ from ubuntu_sso.xdg_base_directory import windows
74+ load_config_paths = windows.load_config_paths
75+ save_config_path = windows.save_config_path
76+ xdg_cache_home = windows.xdg_cache_home
77+ xdg_data_home = windows.xdg_data_home
78+ xdg_data_dirs = windows.xdg_data_dirs
79+else:
80+ import xdg.BaseDirectory
81+ load_config_paths = xdg.BaseDirectory.load_config_paths
82+ save_config_path = xdg.BaseDirectory.save_config_path
83+ xdg_cache_home = xdg.BaseDirectory.xdg_cache_home
84+ xdg_data_home = xdg.BaseDirectory.xdg_data_home
85+ xdg_data_dirs = xdg.BaseDirectory.xdg_data_dirs
86+
87+ubuntuone_log_dir = os.path.join(xdg_cache_home, 'ubuntuone', 'log')
88+if not os.path.exists(ubuntuone_log_dir):
89+ os.makedirs(ubuntuone_log_dir)
90
91=== added directory 'ubuntu_sso/xdg_base_directory/tests'
92=== added file 'ubuntu_sso/xdg_base_directory/tests/__init__.py'
93--- ubuntu_sso/xdg_base_directory/tests/__init__.py 1970-01-01 00:00:00 +0000
94+++ ubuntu_sso/xdg_base_directory/tests/__init__.py 2011-08-23 15:43:28 +0000
95@@ -0,0 +1,16 @@
96+# ubuntu_sso - Ubuntu Single Sign On client support for desktop apps
97+#
98+# Copyright 2009-2010 Canonical Ltd.
99+#
100+# This program is free software: you can redistribute it and/or modify it
101+# under the terms of the GNU General Public License version 3, as published
102+# by the Free Software Foundation.
103+#
104+# This program is distributed in the hope that it will be useful, but
105+# WITHOUT ANY WARRANTY; without even the implied warranties of
106+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
107+# PURPOSE. See the GNU General Public License for more details.
108+#
109+# You should have received a copy of the GNU General Public License along
110+# with this program. If not, see <http://www.gnu.org/licenses/>.
111+"""XDG tests."""
112
113=== added file 'ubuntu_sso/xdg_base_directory/tests/test_common.py'
114--- ubuntu_sso/xdg_base_directory/tests/test_common.py 1970-01-01 00:00:00 +0000
115+++ ubuntu_sso/xdg_base_directory/tests/test_common.py 2011-08-23 15:43:28 +0000
116@@ -0,0 +1,56 @@
117+# -*- coding: utf-8 -*-
118+#
119+# Authors: Natalia B. Bidart <natalia.bidart@canonical.com>
120+#
121+# Copyright 2011 Canonical Ltd.
122+#
123+# This program is free software: you can redistribute it and/or modify it
124+# under the terms of the GNU General Public License version 3, as published
125+# by the Free Software Foundation.
126+#
127+# This program is distributed in the hope that it will be useful, but
128+# WITHOUT ANY WARRANTY; without even the implied warranties of
129+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
130+# PURPOSE. See the GNU General Public License for more details.
131+#
132+# You should have received a copy of the GNU General Public License along
133+# with this program. If not, see <http://www.gnu.org/licenses/>.
134+
135+"""Platform independent tests for the XDG constants."""
136+
137+import os
138+
139+from twisted.trial.unittest import TestCase
140+
141+from ubuntu_sso import xdg_base_directory
142+
143+
144+class TestBaseDirectory(TestCase):
145+ """Tests for the BaseDirectory module."""
146+
147+ def test_ubuntuone_log_dir(self):
148+ """The ubuntuone_log_dir is correct."""
149+ expected = os.path.join(xdg_base_directory.xdg_cache_home,
150+ 'ubuntuone', 'log')
151+ self.assertEqual(expected, xdg_base_directory.ubuntuone_log_dir)
152+ self.assertTrue(os.path.exists(expected))
153+
154+ def test_xdg_cache_home_is_bytes(self):
155+ """The returned path is bytes."""
156+ actual = xdg_base_directory.xdg_cache_home
157+ self.assertIsInstance(actual, str)
158+
159+ def test_xdg_data_home_is_bytes(self):
160+ """The returned path is bytes."""
161+ actual = xdg_base_directory.xdg_data_home
162+ self.assertIsInstance(actual, str)
163+
164+ def test_load_config_paths_filter(self):
165+ """Since those folders don't exist, this should be empty."""
166+ self.assertEqual(list(xdg_base_directory.load_config_paths("x")), [])
167+
168+ def test_save_config_path(self):
169+ """The path should end with xdg_config/x (respecting the separator)."""
170+ self.patch(os, "makedirs", lambda *args: None)
171+ result = xdg_base_directory.save_config_path("x")
172+ self.assertEqual(result.split(os.sep)[-2:], ['xdg_config', 'x'])
173
174=== added file 'ubuntu_sso/xdg_base_directory/tests/test_windows.py'
175--- ubuntu_sso/xdg_base_directory/tests/test_windows.py 1970-01-01 00:00:00 +0000
176+++ ubuntu_sso/xdg_base_directory/tests/test_windows.py 2011-08-23 15:43:28 +0000
177@@ -0,0 +1,112 @@
178+# -*- coding: utf-8 -*-
179+#
180+# Authors: Natalia B. Bidart <natalia.bidart@canonical.com>
181+#
182+# Copyright 2011 Canonical Ltd.
183+#
184+# This program is free software: you can redistribute it and/or modify it
185+# under the terms of the GNU General Public License version 3, as published
186+# by the Free Software Foundation.
187+#
188+# This program is distributed in the hope that it will be useful, but
189+# WITHOUT ANY WARRANTY; without even the implied warranties of
190+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
191+# PURPOSE. See the GNU General Public License for more details.
192+#
193+# You should have received a copy of the GNU General Public License along
194+# with this program. If not, see <http://www.gnu.org/licenses/>.
195+
196+"""Windows-specific tests for the XDG constants."""
197+
198+import os
199+import sys
200+
201+from twisted.trial.unittest import TestCase
202+from ubuntuone.devtools.testcase import skipIfOS
203+
204+
205+# pylint: disable=E1101, E0611, F0401
206+if sys.platform == "win32":
207+ import win32com.shell
208+ from ubuntu_sso.xdg_base_directory.windows import (
209+ get_config_dirs,
210+ get_data_dirs,
211+ get_special_folders,
212+ )
213+
214+
215+# pylint: disable=C0103
216+class FakeShellConModule(object):
217+ """Override CSIDL_ constants."""
218+ CSIDL_PROFILE = 0
219+ CSIDL_LOCAL_APPDATA = 1
220+ CSIDL_COMMON_APPDATA = 2
221+
222+
223+class FakeShellModule(object):
224+
225+ """Fake Shell Module."""
226+
227+ def __init__(self):
228+ """Set the proper mapping between CSIDL_ consts."""
229+ self.values = {
230+ 0: u'c:\\path\\to\\users\\home',
231+ 1: u'c:\\path\\to\\users\\home\\appData\\local',
232+ 2: u'c:\\programData',
233+ }
234+
235+ def SHGetFolderPath(self, dummy0, shellconValue, dummy2, dummy3):
236+ """Override SHGetFolderPath functionality."""
237+ return self.values[shellconValue]
238+
239+
240+@skipIfOS('linux2', 'Windows-specific tests.')
241+class TestBaseDirectoryWindows(TestCase):
242+ """Tests for the BaseDirectory module."""
243+
244+ def test_get_special_folders(self):
245+ """Make sure we can import the platform module."""
246+
247+ shellModule = FakeShellModule()
248+ self.patch(win32com.shell, "shell", shellModule)
249+ self.patch(win32com.shell, "shellcon", FakeShellConModule())
250+ special_folders = get_special_folders()
251+ self.assertTrue('Personal' in special_folders)
252+ self.assertTrue('Local AppData' in special_folders)
253+ self.assertTrue('AppData' in special_folders)
254+ self.assertTrue('Common AppData' in special_folders)
255+
256+ self.assertTrue(special_folders['Personal'] == \
257+ shellModule.values[FakeShellConModule.CSIDL_PROFILE])
258+ self.assertTrue(special_folders['Local AppData'] == \
259+ shellModule.values[FakeShellConModule.CSIDL_LOCAL_APPDATA])
260+ self.assertTrue(special_folders['Local AppData'].startswith(
261+ special_folders['AppData']))
262+ self.assertTrue(special_folders['Common AppData'] == \
263+ shellModule.values[FakeShellConModule.CSIDL_COMMON_APPDATA])
264+
265+ # Can't use assert_syncdaemon_path
266+ for val in special_folders.itervalues():
267+ self.assertIsInstance(val, str)
268+ val.decode('utf8')
269+ # Should not raise exceptions
270+
271+ def test_get_data_dirs(self):
272+ """Check thet get_data_dirs uses pathsep correctly."""
273+ bad_sep = filter(lambda x: x not in os.pathsep, ":;")
274+ dir_list = ["A", "B", bad_sep, "C"]
275+ self.patch(os, "environ",
276+ dict(XDG_DATA_DIRS=os.pathsep.join(
277+ dir_list)))
278+ dirs = get_data_dirs()
279+ self.assertEqual(dirs, dir_list)
280+
281+ def test_get_config_dirs(self):
282+ """Check thet get_data_dirs uses pathsep correctly."""
283+ bad_sep = filter(lambda x: x not in os.pathsep, ":;")
284+ dir_list = ["A", "B", bad_sep, "C"]
285+ self.patch(os, "environ",
286+ dict(XDG_CONFIG_DIRS=os.pathsep.join(
287+ dir_list)))
288+ dirs = get_config_dirs()[1:]
289+ self.assertEqual(dirs, dir_list)
290
291=== added file 'ubuntu_sso/xdg_base_directory/windows.py'
292--- ubuntu_sso/xdg_base_directory/windows.py 1970-01-01 00:00:00 +0000
293+++ ubuntu_sso/xdg_base_directory/windows.py 2011-08-23 15:43:28 +0000
294@@ -0,0 +1,119 @@
295+# Authors: Manuel de la Pena <manuel@canonical.com>
296+# Diego Sarmentero <diego.sarmentero@canonical.com>
297+#
298+# Copyright 2011 Canonical Ltd.
299+#
300+# This program is free software: you can redistribute it and/or modify it
301+# under the terms of the GNU General Public License version 3, as published
302+# by the Free Software Foundation.
303+#
304+# This program is distributed in the hope that it will be useful, but
305+# WITHOUT ANY WARRANTY; without even the implied warranties of
306+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
307+# PURPOSE. See the GNU General Public License for more details.
308+#
309+# You should have received a copy of the GNU General Public License along
310+# with this program. If not, see <http://www.gnu.org/licenses/>.
311+
312+"""XDG helpers for windows."""
313+
314+import os
315+
316+
317+# pylint: disable=C0103
318+def get_special_folders():
319+ """ Routine to grab all the Windows Special Folders locations.
320+
321+ If successful, returns dictionary
322+ of shell folder locations indexed on Windows keyword for each;
323+ otherwise, returns an empty dictionary.
324+ """
325+ # pylint: disable=W0621, F0401, E0611
326+ special_folders = {}
327+
328+ from win32com.shell import shell, shellcon
329+ # CSIDL_LOCAL_APPDATA = C:\Users\<username>\AppData\Local
330+ # CSIDL_PROFILE = C:\Users\<username>
331+ # CSIDL_COMMON_APPDATA = C:\ProgramData
332+ # More information on these at
333+ # http://msdn.microsoft.com/en-us/library/bb762494(v=vs.85).aspx
334+ get_path = lambda name: shell.SHGetFolderPath(
335+ 0, getattr(shellcon, name), None, 0).encode('utf8')
336+ special_folders['Personal'] = get_path("CSIDL_PROFILE")
337+ special_folders['Local AppData'] = get_path("CSIDL_LOCAL_APPDATA")
338+ special_folders['AppData'] = os.path.dirname(
339+ special_folders['Local AppData'])
340+ special_folders['Common AppData'] = get_path("CSIDL_COMMON_APPDATA")
341+ return special_folders
342+
343+special_folders = get_special_folders()
344+
345+home_path = special_folders['Personal']
346+app_local_data_path = special_folders['Local AppData']
347+app_global_data_path = special_folders['Common AppData']
348+
349+# use the non roaming app data
350+xdg_data_home = os.environ.get('XDG_DATA_HOME',
351+ os.path.join(app_local_data_path, 'xdg'))
352+
353+
354+def get_data_dirs():
355+ """Returns XDG data directories."""
356+ return os.environ.get('XDG_DATA_DIRS',
357+ '{0}{1}{2}'.format(app_local_data_path, os.pathsep,
358+ app_global_data_path)).split(os.pathsep)
359+
360+xdg_data_dirs = get_data_dirs()
361+
362+# we will return the roaming data wich is as close as we get in windows
363+# regarding caching.
364+xdg_cache_home = os.environ.get('XDG_CACHE_HOME',
365+ os.path.join(xdg_data_home, 'cache'))
366+
367+# point to the not roaming app data for the user
368+xdg_config_home = os.environ.get('XDG_CONFIG_HOME',
369+ app_local_data_path)
370+
371+
372+def get_config_dirs():
373+ """Return XDG config directories."""
374+ return [xdg_config_home] + \
375+ os.environ.get('XDG_CONFIG_DIRS',
376+ app_global_data_path,
377+ ).split(os.pathsep)
378+
379+xdg_config_dirs = get_config_dirs()
380+
381+xdg_data_dirs = filter(lambda x: x, xdg_data_dirs)
382+xdg_config_dirs = filter(lambda x: x, xdg_config_dirs)
383+
384+
385+def load_config_paths(*resource):
386+ """Iterator of configuration paths.
387+
388+ Return an iterator which gives each directory named 'resource' in
389+ the configuration search path. Information provided by earlier
390+ directories should take precedence over later ones (ie, the user's
391+ config dir comes first).
392+ """
393+ resource = os.path.join(*resource)
394+ for config_dir in xdg_config_dirs:
395+ path = os.path.join(config_dir, resource)
396+ if os.path.exists(path):
397+ yield path
398+
399+
400+def save_config_path(*resource):
401+ """Path to save configuration.
402+
403+ Ensure $XDG_CONFIG_HOME/<resource>/ exists, and return its path.
404+ 'resource' should normally be the name of your application. Use this
405+ when SAVING configuration settings. Use the xdg_config_dirs variable
406+ for loading.
407+ """
408+ resource = os.path.join(*resource)
409+ assert not resource.startswith('/')
410+ path = os.path.join(xdg_config_home, resource)
411+ if not os.path.isdir(path):
412+ os.makedirs(path, 0700)
413+ return path

Subscribers

People subscribed via source and target branches