Use ZEROINSTALL_PORTABLE_BASE environment variable to override normal XDG directory...
[zeroinstall/solver.git] / zeroinstall / support / basedir.py
blob53afea0b3103f0db97d1df2cd9f11d9dc4548098
1 """
2 Support code for the freedesktop.org basedir spec.
4 This module provides functions for locating configuration files.
6 @see: U{http://freedesktop.org/wiki/Standards/basedir-spec}
8 @var home: The value of $HOME (or '/' if not set). If we're running as root and
9 $HOME isn't owned by root, then this will be root's home from /etc/passwd
10 instead.
11 """
13 # Copyright (C) 2009, Thomas Leonard
14 # See the README file for details, or visit http://0install.net.
16 from zeroinstall import _
17 import os
19 home = os.environ.get('HOME', '/')
21 try:
22 _euid = os.geteuid()
23 except AttributeError:
24 pass # Windows?
25 else:
26 if _euid == 0:
27 # We're running as root. Ensure that $HOME really is root's home,
28 # not the user's home, or we're likely to fill it will unreadable
29 # root-owned files.
30 home_owner = os.stat(home).st_uid
31 if home_owner != 0:
32 import pwd
33 from logging import info
34 old_home = home
35 home = pwd.getpwuid(0).pw_dir or '/'
36 info(_("$HOME (%(home)s) is owned by user %(user)d, but we are root (0). Using %(root_home)s instead."), {'home': old_home, 'user': home_owner, 'root_home': home})
37 del old_home
38 del home_owner
40 portable_base = os.environ.get('ZEROINSTALL_PORTABLE_BASE')
41 if portable_base:
42 xdg_data_home = os.path.join(portable_base, "data")
43 xdg_data_dirs = [xdg_data_home]
44 xdg_cache_home = os.path.join(portable_base, "cache")
45 xdg_cache_dirs = [xdg_cache_home]
46 xdg_config_home = os.path.join(portable_base, "config")
47 xdg_config_dirs = [xdg_config_home]
48 elif os.name == "nt":
49 from win32com.shell import shell, shellcon
50 appData = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)
51 localAppData = shell.SHGetFolderPath(0, shellcon.CSIDL_LOCAL_APPDATA, 0, 0)
52 commonAppData = shell.SHGetFolderPath(0, shellcon.CSIDL_COMMON_APPDATA, 0, 0)
54 xdg_data_home = appData
55 xdg_data_dirs = [xdg_data_home, commonAppData]
57 xdg_cache_home = localAppData
58 xdg_cache_dirs = [xdg_cache_home, commonAppData]
60 xdg_config_home = appData
61 xdg_config_dirs = [xdg_config_home, commonAppData]
62 else:
63 xdg_data_home = os.environ.get('XDG_DATA_HOME',
64 os.path.join(home, '.local', 'share'))
66 xdg_data_dirs = [xdg_data_home] + \
67 os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':')
69 xdg_cache_home = os.environ.get('XDG_CACHE_HOME',
70 os.path.join(home, '.cache'))
72 xdg_cache_dirs = [xdg_cache_home] + \
73 os.environ.get('XDG_CACHE_DIRS', '/var/cache').split(':')
75 xdg_config_home = os.environ.get('XDG_CONFIG_HOME',
76 os.path.join(home, '.config'))
78 xdg_config_dirs = [xdg_config_home] + \
79 os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg').split(':')
81 xdg_data_dirs = filter(lambda x: x, xdg_data_dirs)
82 xdg_cache_dirs = filter(lambda x: x, xdg_cache_dirs)
83 xdg_config_dirs = filter(lambda x: x, xdg_config_dirs)
85 def save_config_path(*resource):
86 """Ensure $XDG_CONFIG_HOME/<resource>/ exists, and return its path.
87 'resource' should normally be the name of your application. Use this
88 when SAVING configuration settings. Use the xdg_config_dirs variable
89 for loading."""
90 resource = os.path.join(*resource)
91 assert not os.path.isabs(resource)
92 path = os.path.join(xdg_config_home, resource)
93 if not os.path.isdir(path):
94 os.makedirs(path, 0o700)
95 return path
97 def load_config_paths(*resource):
98 """Returns an iterator which gives each directory named 'resource' in the
99 configuration search path. Information provided by earlier directories should
100 take precedence over later ones (ie, the user's config dir comes first)."""
101 resource = os.path.join(*resource)
102 for config_dir in xdg_config_dirs:
103 path = os.path.join(config_dir, resource)
104 if os.path.exists(path): yield path
106 def load_first_config(*resource):
107 """Returns the first result from load_config_paths, or None if there is nothing
108 to load."""
109 for x in load_config_paths(*resource):
110 return x
111 return None
113 def save_cache_path(*resource):
114 """Ensure $XDG_CACHE_HOME/<resource>/ exists, and return its path.
115 'resource' should normally be the name of your application."""
116 resource = os.path.join(*resource)
117 assert not os.path.isabs(resource)
118 path = os.path.join(xdg_cache_home, resource)
119 if not os.path.isdir(path):
120 os.makedirs(path, 0o700)
121 return path
123 def load_cache_paths(*resource):
124 """Returns an iterator which gives each directory named 'resource' in the
125 cache search path. Information provided by earlier directories should
126 take precedence over later ones (ie, the user's cache dir comes first)."""
127 resource = os.path.join(*resource)
128 for cache_dir in xdg_cache_dirs:
129 path = os.path.join(cache_dir, resource)
130 if os.path.exists(path): yield path
132 def load_first_cache(*resource):
133 """Returns the first result from load_cache_paths, or None if there is nothing
134 to load."""
135 for x in load_cache_paths(*resource):
136 return x
137 return None
139 def load_data_paths(*resource):
140 """Returns an iterator which gives each directory named 'resource' in the
141 shared data search path. Information provided by earlier directories should
142 take precedence over later ones.
143 @since: 0.28"""
144 resource = os.path.join(*resource)
145 for data_dir in xdg_data_dirs:
146 path = os.path.join(data_dir, resource)
147 if os.path.exists(path): yield path
149 def load_first_data(*resource):
150 """Returns the first result from load_data_paths, or None if there is nothing
151 to load.
152 @since: 0.28"""
153 for x in load_data_paths(*resource):
154 return x
155 return None