Cope better with being run through sudo
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / support / basedir.py
blob92bdf07202c7ec0ef4774f06167488e0acf315de
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) 2006, Thomas Leonard
14 # See the README file for details, or visit http://0install.net.
16 import os
18 home = os.environ.get('HOME', '/')
20 if os.geteuid() == 0:
21 # We're running as root. Ensure that $HOME really is root's home,
22 # not the user's home, or we're likely to fill it will unreadable
23 # root-owned files.
24 home_owner = os.stat(home).st_uid
25 if home_owner != 0:
26 import pwd
27 from logging import info
28 old_home = home
29 home = pwd.getpwuid(0).pw_dir or '/'
30 info("$HOME (%s) is owned by user %d, but we are root (0). Using %s instead.", old_home, home_owner, home)
31 del old_home
32 del home_owner
34 xdg_data_home = os.environ.get('XDG_DATA_HOME',
35 os.path.join(home, '.local', 'share'))
37 xdg_data_dirs = [xdg_data_home] + \
38 os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':')
40 xdg_cache_home = os.environ.get('XDG_CACHE_HOME',
41 os.path.join(home, '.cache'))
43 xdg_cache_dirs = [xdg_cache_home] + \
44 os.environ.get('XDG_CACHE_DIRS', '/var/cache').split(':')
46 xdg_config_home = os.environ.get('XDG_CONFIG_HOME',
47 os.path.join(home, '.config'))
49 xdg_config_dirs = [xdg_config_home] + \
50 os.environ.get('XDG_CONFIG_DIRS', '/etc/xdg').split(':')
52 xdg_data_dirs = filter(lambda x: x, xdg_data_dirs)
53 xdg_cache_dirs = filter(lambda x: x, xdg_cache_dirs)
54 xdg_config_dirs = filter(lambda x: x, xdg_config_dirs)
56 def save_config_path(*resource):
57 """Ensure $XDG_CONFIG_HOME/<resource>/ exists, and return its path.
58 'resource' should normally be the name of your application. Use this
59 when SAVING configuration settings. Use the xdg_config_dirs variable
60 for loading."""
61 resource = os.path.join(*resource)
62 assert not resource.startswith('/')
63 path = os.path.join(xdg_config_home, resource)
64 if not os.path.isdir(path):
65 os.makedirs(path, 0700)
66 return path
68 def load_config_paths(*resource):
69 """Returns an iterator which gives each directory named 'resource' in the
70 configuration search path. Information provided by earlier directories should
71 take precedence over later ones (ie, the user's config dir comes first)."""
72 resource = os.path.join(*resource)
73 for config_dir in xdg_config_dirs:
74 path = os.path.join(config_dir, resource)
75 if os.path.exists(path): yield path
77 def load_first_config(*resource):
78 """Returns the first result from load_config_paths, or None if there is nothing
79 to load."""
80 for x in load_config_paths(*resource):
81 return x
82 return None
84 def save_cache_path(*resource):
85 """Ensure $XDG_CACHE_HOME/<resource>/ exists, and return its path.
86 'resource' should normally be the name of your application."""
87 resource = os.path.join(*resource)
88 assert not resource.startswith('/')
89 path = os.path.join(xdg_cache_home, resource)
90 if not os.path.isdir(path):
91 os.makedirs(path, 0700)
92 return path
94 def load_cache_paths(*resource):
95 """Returns an iterator which gives each directory named 'resource' in the
96 cache search path. Information provided by earlier directories should
97 take precedence over later ones (ie, the user's cache dir comes first)."""
98 resource = os.path.join(*resource)
99 for cache_dir in xdg_cache_dirs:
100 path = os.path.join(cache_dir, resource)
101 if os.path.exists(path): yield path
103 def load_first_cache(*resource):
104 """Returns the first result from load_cache_paths, or None if there is nothing
105 to load."""
106 for x in load_cache_paths(*resource):
107 return x
108 return None
110 def load_data_paths(*resource):
111 """Returns an iterator which gives each directory named 'resource' in the
112 shared data search path. Information provided by earlier directories should
113 take precedence over later ones.
114 @since: 0.28"""
115 resource = os.path.join(*resource)
116 for data_dir in xdg_data_dirs:
117 path = os.path.join(data_dir, resource)
118 if os.path.exists(path): yield path
120 def load_first_data(*resource):
121 """Returns the first result from load_data_paths, or None if there is nothing
122 to load.
123 @since: 0.28"""
124 for x in load_data_paths(*resource):
125 return x
126 return None