[IMP] translations: simplify condition in qweb terms extraction
[odoo/odoo.git] / openerp / tools / appdirs.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright (c) 2005-2010 ActiveState Software Inc.
4 # Copyright (c) 2013 Eddy PetriČ™or
5
6 """Utilities for determining application-specific dirs.
7
8 See <http://github.com/ActiveState/appdirs> for details and usage.
9 """
10 # Dev Notes:
11 # - MSDN on where to store app data files:
12 #   http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
13 # - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
14 # - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
15
16 __version_info__ = (1, 3, 0)
17 __version__ = '.'.join(map(str, __version_info__))
18
19
20 import sys
21 import os
22
23 PY3 = sys.version_info[0] == 3
24
25 if PY3:
26     unicode = str
27
28
29
30 def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
31     r"""Return full path to the user-specific data dir for this application.
32
33         "appname" is the name of application.
34             If None, just the system directory is returned.
35         "appauthor" (only required and used on Windows) is the name of the
36             appauthor or distributing body for this application. Typically
37             it is the owning company name. This falls back to appname.
38         "version" is an optional version path element to append to the
39             path. You might want to use this if you want multiple versions
40             of your app to be able to run independently. If used, this
41             would typically be "<major>.<minor>".
42             Only applied when appname is present.
43         "roaming" (boolean, default False) can be set True to use the Windows
44             roaming appdata directory. That means that for users on a Windows
45             network setup for roaming profiles, this user data will be
46             sync'd on login. See
47             <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
48             for a discussion of issues.
49
50     Typical user data directories are:
51         Mac OS X:               ~/Library/Application Support/<AppName>
52         Unix:                   ~/.local/share/<AppName>    # or in $XDG_DATA_HOME, if defined
53         Win XP (not roaming):   C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
54         Win XP (roaming):       C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
55         Win 7  (not roaming):   C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
56         Win 7  (roaming):       C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
57
58     For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
59     That means, by deafult "~/.local/share/<AppName>".
60     """
61     if sys.platform == "win32":
62         if appauthor is None:
63             appauthor = appname
64         const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
65         path = os.path.normpath(_get_win_folder(const))
66         if appname:
67             path = os.path.join(path, appauthor, appname)
68     elif sys.platform == 'darwin':
69         path = os.path.expanduser('~/Library/Application Support/')
70         if appname:
71             path = os.path.join(path, appname)
72     else:
73         path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
74         if appname:
75             path = os.path.join(path, appname)
76     if appname and version:
77         path = os.path.join(path, version)
78     return path
79
80
81 def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
82     """Return full path to the user-shared data dir for this application.
83
84         "appname" is the name of application.
85             If None, just the system directory is returned.
86         "appauthor" (only required and used on Windows) is the name of the
87             appauthor or distributing body for this application. Typically
88             it is the owning company name. This falls back to appname.
89         "version" is an optional version path element to append to the
90             path. You might want to use this if you want multiple versions
91             of your app to be able to run independently. If used, this
92             would typically be "<major>.<minor>".
93             Only applied when appname is present.
94         "multipath" is an optional parameter only applicable to *nix
95             which indicates that the entire list of data dirs should be
96             returned. By default, the first item from XDG_DATA_DIRS is
97             returned, or '/usr/local/share/<AppName>',
98             if XDG_DATA_DIRS is not set
99
100     Typical user data directories are:
101         Mac OS X:   /Library/Application Support/<AppName>
102         Unix:       /usr/local/share/<AppName> or /usr/share/<AppName>
103         Win XP:     C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
104         Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
105         Win 7:      C:\ProgramData\<AppAuthor>\<AppName>   # Hidden, but writeable on Win 7.
106
107     For Unix, this is using the $XDG_DATA_DIRS[0] default.
108
109     WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
110     """
111     if sys.platform == "win32":
112         if appauthor is None:
113             appauthor = appname
114         path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
115         if appname:
116             path = os.path.join(path, appauthor, appname)
117     elif sys.platform == 'darwin':
118         path = os.path.expanduser('/Library/Application Support')
119         if appname:
120             path = os.path.join(path, appname)
121     else:
122         # XDG default for $XDG_DATA_DIRS
123         # only first, if multipath is False
124         path = os.getenv('XDG_DATA_DIRS',
125                         os.pathsep.join(['/usr/local/share', '/usr/share']))
126         pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ]
127         if appname:
128             if version:
129                 appname = os.path.join(appname, version)
130             pathlist = [ os.sep.join([x, appname]) for x in pathlist ]
131
132         if multipath:
133             path = os.pathsep.join(pathlist)
134         else:
135             path = pathlist[0]
136         return path
137
138     if appname and version:
139         path = os.path.join(path, version)
140     return path
141
142
143 def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
144     r"""Return full path to the user-specific config dir for this application.
145
146         "appname" is the name of application.
147             If None, just the system directory is returned.
148         "appauthor" (only required and used on Windows) is the name of the
149             appauthor or distributing body for this application. Typically
150             it is the owning company name. This falls back to appname.
151         "version" is an optional version path element to append to the
152             path. You might want to use this if you want multiple versions
153             of your app to be able to run independently. If used, this
154             would typically be "<major>.<minor>".
155             Only applied when appname is present.
156         "roaming" (boolean, default False) can be set True to use the Windows
157             roaming appdata directory. That means that for users on a Windows
158             network setup for roaming profiles, this user data will be
159             sync'd on login. See
160             <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
161             for a discussion of issues.
162
163     Typical user data directories are:
164         Mac OS X:               same as user_data_dir
165         Unix:                   ~/.config/<AppName>     # or in $XDG_CONFIG_HOME, if defined
166         Win *:                  same as user_data_dir
167
168     For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
169     That means, by deafult "~/.local/share/<AppName>".
170     """
171     if sys.platform in [ "win32", "darwin" ]:
172         path = user_data_dir(appname, appauthor, None, roaming)
173     else:
174         path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
175         if appname:
176             path = os.path.join(path, appname)
177     if appname and version:
178         path = os.path.join(path, version)
179     return path
180
181
182 def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
183     """Return full path to the user-shared data dir for this application.
184
185         "appname" is the name of application.
186             If None, just the system directory is returned.
187         "appauthor" (only required and used on Windows) is the name of the
188             appauthor or distributing body for this application. Typically
189             it is the owning company name. This falls back to appname.
190         "version" is an optional version path element to append to the
191             path. You might want to use this if you want multiple versions
192             of your app to be able to run independently. If used, this
193             would typically be "<major>.<minor>".
194             Only applied when appname is present.
195         "multipath" is an optional parameter only applicable to *nix
196             which indicates that the entire list of config dirs should be
197             returned. By default, the first item from XDG_CONFIG_DIRS is
198             returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
199
200     Typical user data directories are:
201         Mac OS X:   same as site_data_dir
202         Unix:       /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
203                     $XDG_CONFIG_DIRS
204         Win *:      same as site_data_dir
205         Vista:      (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
206
207     For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
208
209     WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
210     """
211     if sys.platform in [ "win32", "darwin" ]:
212         path = site_data_dir(appname, appauthor)
213         if appname and version:
214             path = os.path.join(path, version)
215     else:
216         # XDG default for $XDG_CONFIG_DIRS
217         # only first, if multipath is False
218         path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
219         pathlist = [ os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) ]
220         if appname:
221             if version:
222                 appname = os.path.join(appname, version)
223             pathlist = [ os.sep.join([x, appname]) for x in pathlist ]
224
225         if multipath:
226             path = os.pathsep.join(pathlist)
227         else:
228             path = pathlist[0]
229     return path
230
231 def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
232     r"""Return full path to the user-specific cache dir for this application.
233
234         "appname" is the name of application.
235             If None, just the system directory is returned.
236         "appauthor" (only required and used on Windows) is the name of the
237             appauthor or distributing body for this application. Typically
238             it is the owning company name. This falls back to appname.
239         "version" is an optional version path element to append to the
240             path. You might want to use this if you want multiple versions
241             of your app to be able to run independently. If used, this
242             would typically be "<major>.<minor>".
243             Only applied when appname is present.
244         "opinion" (boolean) can be False to disable the appending of
245             "Cache" to the base app data dir for Windows. See
246             discussion below.
247
248     Typical user cache directories are:
249         Mac OS X:   ~/Library/Caches/<AppName>
250         Unix:       ~/.cache/<AppName> (XDG default)
251         Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
252         Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
253
254     On Windows the only suggestion in the MSDN docs is that local settings go in
255     the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
256     app data dir (the default returned by `user_data_dir` above). Apps typically
257     put cache data somewhere *under* the given dir here. Some examples:
258         ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
259         ...\Acme\SuperApp\Cache\1.0
260     OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
261     This can be disabled with the `opinion=False` option.
262     """
263     if sys.platform == "win32":
264         if appauthor is None:
265             appauthor = appname
266         path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
267         if appname:
268             path = os.path.join(path, appauthor, appname)
269             if opinion:
270                 path = os.path.join(path, "Cache")
271     elif sys.platform == 'darwin':
272         path = os.path.expanduser('~/Library/Caches')
273         if appname:
274             path = os.path.join(path, appname)
275     else:
276         path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
277         if appname:
278             path = os.path.join(path, appname)
279     if appname and version:
280         path = os.path.join(path, version)
281     return path
282
283 def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
284     r"""Return full path to the user-specific log dir for this application.
285
286         "appname" is the name of application.
287             If None, just the system directory is returned.
288         "appauthor" (only required and used on Windows) is the name of the
289             appauthor or distributing body for this application. Typically
290             it is the owning company name. This falls back to appname.
291         "version" is an optional version path element to append to the
292             path. You might want to use this if you want multiple versions
293             of your app to be able to run independently. If used, this
294             would typically be "<major>.<minor>".
295             Only applied when appname is present.
296         "opinion" (boolean) can be False to disable the appending of
297             "Logs" to the base app data dir for Windows, and "log" to the
298             base cache dir for Unix. See discussion below.
299
300     Typical user cache directories are:
301         Mac OS X:   ~/Library/Logs/<AppName>
302         Unix:       ~/.cache/<AppName>/log  # or under $XDG_CACHE_HOME if defined
303         Win XP:     C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
304         Vista:      C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
305
306     On Windows the only suggestion in the MSDN docs is that local settings
307     go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
308     examples of what some windows apps use for a logs dir.)
309
310     OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
311     value for Windows and appends "log" to the user cache dir for Unix.
312     This can be disabled with the `opinion=False` option.
313     """
314     if sys.platform == "darwin":
315         path = os.path.join(
316             os.path.expanduser('~/Library/Logs'),
317             appname)
318     elif sys.platform == "win32":
319         path = user_data_dir(appname, appauthor, version); version=False
320         if opinion:
321             path = os.path.join(path, "Logs")
322     else:
323         path = user_cache_dir(appname, appauthor, version); version=False
324         if opinion:
325             path = os.path.join(path, "log")
326     if appname and version:
327         path = os.path.join(path, version)
328     return path
329
330
331 class AppDirs(object):
332     """Convenience wrapper for getting application dirs."""
333     def __init__(self, appname, appauthor=None, version=None,
334                     roaming=False, multipath=False):
335         self.appname = appname
336         self.appauthor = appauthor
337         self.version = version
338         self.roaming = roaming
339         self.multipath = multipath
340     @property
341     def user_data_dir(self):
342         return user_data_dir(self.appname, self.appauthor,
343             version=self.version, roaming=self.roaming)
344     @property
345     def site_data_dir(self):
346         return site_data_dir(self.appname, self.appauthor,
347             version=self.version, multipath=self.multipath)
348     @property
349     def user_config_dir(self):
350         return user_config_dir(self.appname, self.appauthor,
351             version=self.version, roaming=self.roaming)
352     @property
353     def site_config_dir(self):
354         return site_data_dir(self.appname, self.appauthor,
355             version=self.version, multipath=self.multipath)
356     @property
357     def user_cache_dir(self):
358         return user_cache_dir(self.appname, self.appauthor,
359             version=self.version)
360     @property
361     def user_log_dir(self):
362         return user_log_dir(self.appname, self.appauthor,
363             version=self.version)
364
365
366
367
368 #---- internal support stuff
369
370 def _get_win_folder_from_registry(csidl_name):
371     """This is a fallback technique at best. I'm not sure if using the
372     registry for this guarantees us the correct answer for all CSIDL_*
373     names.
374     """
375     import _winreg
376
377     shell_folder_name = {
378         "CSIDL_APPDATA": "AppData",
379         "CSIDL_COMMON_APPDATA": "Common AppData",
380         "CSIDL_LOCAL_APPDATA": "Local AppData",
381     }[csidl_name]
382
383     key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
384         r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
385     dir, type = _winreg.QueryValueEx(key, shell_folder_name)
386     return dir
387
388 def _get_win_folder_with_pywin32(csidl_name):
389     from win32com.shell import shellcon, shell
390     dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
391     # Try to make this a unicode path because SHGetFolderPath does
392     # not return unicode strings when there is unicode data in the
393     # path.
394     try:
395         dir = unicode(dir)
396
397         # Downgrade to short path name if have highbit chars. See
398         # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
399         has_high_char = False
400         for c in dir:
401             if ord(c) > 255:
402                 has_high_char = True
403                 break
404         if has_high_char:
405             try:
406                 import win32api
407                 dir = win32api.GetShortPathName(dir)
408             except ImportError:
409                 pass
410     except UnicodeError:
411         pass
412     return dir
413
414 def _get_win_folder_with_ctypes(csidl_name):
415     import ctypes
416
417     csidl_const = {
418         "CSIDL_APPDATA": 26,
419         "CSIDL_COMMON_APPDATA": 35,
420         "CSIDL_LOCAL_APPDATA": 28,
421     }[csidl_name]
422
423     buf = ctypes.create_unicode_buffer(1024)
424     ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
425
426     # Downgrade to short path name if have highbit chars. See
427     # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
428     has_high_char = False
429     for c in buf:
430         if ord(c) > 255:
431             has_high_char = True
432             break
433     if has_high_char:
434         buf2 = ctypes.create_unicode_buffer(1024)
435         if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
436             buf = buf2
437
438     return buf.value
439
440 if sys.platform == "win32":
441     try:
442         import win32com.shell
443         _get_win_folder = _get_win_folder_with_pywin32
444     except ImportError:
445         try:
446             import ctypes
447             _get_win_folder = _get_win_folder_with_ctypes
448         except ImportError:
449             _get_win_folder = _get_win_folder_from_registry
450
451
452
453 #---- self test code
454
455 if __name__ == "__main__":
456     appname = "MyApp"
457     appauthor = "MyCompany"
458
459     props = ("user_data_dir", "site_data_dir",
460              "user_config_dir", "site_config_dir",
461              "user_cache_dir", "user_log_dir")
462
463     print("-- app dirs (with optional 'version')")
464     dirs = AppDirs(appname, appauthor, version="1.0")
465     for prop in props:
466         print("%s: %s" % (prop, getattr(dirs, prop)))
467
468     print("\n-- app dirs (without optional 'version')")
469     dirs = AppDirs(appname, appauthor)
470     for prop in props:
471         print("%s: %s" % (prop, getattr(dirs, prop)))
472
473     print("\n-- app dirs (without optional 'appauthor')")
474     dirs = AppDirs(appname)
475     for prop in props:
476         print("%s: %s" % (prop, getattr(dirs, prop)))
477