~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Robert Collins
  • Date: 2005-10-14 02:17:36 UTC
  • mfrom: (1185.16.34)
  • Revision ID: robertc@lifelesslap.robertcollins.net-20051014021736-7230e59066856096
MergeĀ fromĀ Martin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""Configuration that affects the behaviour of Bazaar."""
 
19
 
 
20
from ConfigParser import ConfigParser
 
21
import os
 
22
import errno
 
23
import re
 
24
 
 
25
import bzrlib
 
26
import bzrlib.errors as errors
 
27
 
 
28
 
 
29
class Config(object):
 
30
    """A configuration policy - what username, editor, gpg needs etc."""
 
31
 
 
32
    def get_editor(self):
 
33
        """Get the users pop up editor."""
 
34
        raise NotImplementedError
 
35
 
 
36
    def __init__(self):
 
37
        super(Config, self).__init__()
 
38
 
 
39
    def user_email(self):
 
40
        """Return just the email component of a username."""
 
41
        e = self.username()
 
42
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
43
        if not m:
 
44
            raise BzrError("%r doesn't seem to contain "
 
45
                           "a reasonable email address" % e)
 
46
        return m.group(0)
 
47
 
 
48
    def username(self):
 
49
        """Return email-style username.
 
50
    
 
51
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
 
52
        
 
53
        $BZREMAIL can be set to override this, then
 
54
        the concrete policy type is checked, and finally
 
55
        $EMAIL is examinged.
 
56
        but if none is found, a reasonable default is (hopefully)
 
57
        created.
 
58
    
 
59
        TODO: Check it's reasonably well-formed.
 
60
        """
 
61
        v = os.environ.get('BZREMAIL')
 
62
        if v:
 
63
            return v.decode(bzrlib.user_encoding)
 
64
    
 
65
        v = self._get_user_id()
 
66
        if v:
 
67
            return v
 
68
        
 
69
        v = os.environ.get('EMAIL')
 
70
        if v:
 
71
            return v.decode(bzrlib.user_encoding)
 
72
 
 
73
        name, email = _auto_user_id()
 
74
        if name:
 
75
            return '%s <%s>' % (name, email)
 
76
        else:
 
77
            return email
 
78
 
 
79
 
 
80
class GlobalConfig(Config):
 
81
    """The configuration that should be used for a specific location."""
 
82
 
 
83
    def _get_parser(self, filename=None, file=None):
 
84
        parser = ConfigParser()
 
85
        if file is not None:
 
86
            parser.readfp(file)
 
87
        else:
 
88
            parser.read([filename])
 
89
        return parser
 
90
 
 
91
    def _get_config_parser(self, file=None):
 
92
        if self._parser is None:
 
93
            self._parser =  self._get_parser(config_filename(), file)
 
94
        return self._parser
 
95
    
 
96
    def _get_branches_config_parser(self, file=None):
 
97
        if self._branches_parser is None:
 
98
            self._branches_parser = self._get_parser(
 
99
                branches_config_filename(), file)
 
100
        return self._branches_parser
 
101
 
 
102
    def get_editor(self):
 
103
        if self._get_config_parser().has_option('DEFAULT', 'editor'):
 
104
            return self._get_config_parser().get('DEFAULT', 'editor')
 
105
 
 
106
    def _get_user_id(self, branch=None):
 
107
        """Return the full user id from the global config file.
 
108
    
 
109
        e.g. "John Hacker <jhacker@foo.org>"
 
110
        from 
 
111
        [DEFAULT]
 
112
        email=John Hacker <jhacker@foo.org>
 
113
        """
 
114
        if self._get_config_parser().has_option('DEFAULT', 'email'):
 
115
            email = self._get_config_parser().get('DEFAULT', 'email')
 
116
            if email is not None:
 
117
                return email
 
118
    
 
119
    def __init__(self):
 
120
        super(GlobalConfig, self).__init__()
 
121
        self._branches_parser = None
 
122
        self._parser = None
 
123
 
 
124
 
 
125
class LocationConfig(Config):
 
126
    """A configuration object that gives the policy for a location."""
 
127
 
 
128
    def __init__(self, location):
 
129
        self._global_config = None
 
130
        self.location = location
 
131
 
 
132
    def _get_branches_config_parser(self, file=None):
 
133
        return self._get_global_config()._get_branches_config_parser(file)
 
134
 
 
135
    def _get_global_config(self):
 
136
        if self._global_config is None:
 
137
            self._global_config = GlobalConfig()
 
138
        return self._global_config
 
139
 
 
140
    def _get_user_id(self):
 
141
        return self._get_global_config()._get_user_id()
 
142
 
 
143
 
 
144
class BranchConfig(Config):
 
145
    """A configuration object giving the policy for a branch."""
 
146
 
 
147
    def _get_location_config(self):
 
148
        if self._location_config is None:
 
149
            self._location_config = LocationConfig(self.branch.base)
 
150
        return self._location_config
 
151
 
 
152
    def _get_user_id(self):
 
153
        """Return the full user id for the branch.
 
154
    
 
155
        e.g. "John Hacker <jhacker@foo.org>"
 
156
        This is looked up in the email controlfile for the branch.
 
157
        """
 
158
        try:
 
159
            return (self.branch.controlfile("email", "r") 
 
160
                    .read()
 
161
                    .decode(bzrlib.user_encoding)
 
162
                    .rstrip("\r\n"))
 
163
        except errors.NoSuchFile, e:
 
164
            pass
 
165
        
 
166
        return self._get_location_config()._get_user_id()
 
167
 
 
168
    def __init__(self, branch):
 
169
        super(BranchConfig, self).__init__()
 
170
        self._location_config = None
 
171
        self.branch = branch
 
172
 
 
173
 
 
174
def config_dir():
 
175
    """Return per-user configuration directory.
 
176
 
 
177
    By default this is ~/.bazaar/
 
178
    
 
179
    TODO: Global option --config-dir to override this.
 
180
    """
 
181
    return os.path.join(os.path.expanduser("~"), ".bazaar")
 
182
 
 
183
 
 
184
def config_filename():
 
185
    """Return per-user configuration ini file filename."""
 
186
    return os.path.join(config_dir(), 'bazaar.conf')
 
187
 
 
188
 
 
189
def branches_config_filename():
 
190
    """Return per-user configuration ini file filename."""
 
191
    return os.path.join(config_dir(), 'branches.conf')
 
192
 
 
193
 
 
194
def _auto_user_id():
 
195
    """Calculate automatic user identification.
 
196
 
 
197
    Returns (realname, email).
 
198
 
 
199
    Only used when none is set in the environment or the id file.
 
200
 
 
201
    This previously used the FQDN as the default domain, but that can
 
202
    be very slow on machines where DNS is broken.  So now we simply
 
203
    use the hostname.
 
204
    """
 
205
    import socket
 
206
 
 
207
    # XXX: Any good way to get real user name on win32?
 
208
 
 
209
    try:
 
210
        import pwd
 
211
        uid = os.getuid()
 
212
        w = pwd.getpwuid(uid)
 
213
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
214
        username = w.pw_name.decode(bzrlib.user_encoding)
 
215
        comma = gecos.find(',')
 
216
        if comma == -1:
 
217
            realname = gecos
 
218
        else:
 
219
            realname = gecos[:comma]
 
220
        if not realname:
 
221
            realname = username
 
222
 
 
223
    except ImportError:
 
224
        import getpass
 
225
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
 
226
 
 
227
    return realname, (username + '@' + socket.gethostname())
 
228
 
 
229