/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
14
14
#
15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
 
19
19
"""Configuration that affects the behaviour of Bazaar.
20
20
 
37
37
[/home/robertc/source]
38
38
recurse=False|True(default)
39
39
email= as above
40
 
check_signatures= as above 
 
40
check_signatures= as above
41
41
create_signatures= as above.
42
42
 
43
43
explanation of options
45
45
editor - this option sets the pop up editor to use during commits.
46
46
email - this option sets the user id bzr will use when committing.
47
47
check_signatures - this option controls whether bzr will require good gpg
48
 
                   signatures, ignore them, or check them if they are 
 
48
                   signatures, ignore them, or check them if they are
49
49
                   present.
50
 
create_signatures - this option controls whether bzr will always create 
 
50
create_signatures - this option controls whether bzr will always create
51
51
                    gpg signatures, never create them, or create them if the
52
52
                    branch is configured to require them.
53
53
log_format - this option sets the default log format.  Possible values are
78
78
    errors,
79
79
    mail_client,
80
80
    osutils,
 
81
    registry,
81
82
    symbol_versioning,
82
83
    trace,
83
84
    ui,
145
146
class Config(object):
146
147
    """A configuration policy - what username, editor, gpg needs etc."""
147
148
 
 
149
    def __init__(self):
 
150
        super(Config, self).__init__()
 
151
 
148
152
    def get_editor(self):
149
153
        """Get the users pop up editor."""
150
154
        raise NotImplementedError
151
155
 
 
156
    def get_change_editor(self, old_tree, new_tree):
 
157
        from bzrlib import diff
 
158
        cmd = self._get_change_editor()
 
159
        if cmd is None:
 
160
            return None
 
161
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
 
162
                                             sys.stdout)
 
163
 
 
164
 
152
165
    def get_mail_client(self):
153
166
        """Get a mail client to use"""
154
167
        selected_client = self.get_user_option('mail_client')
173
186
        """Get a generic option - no special process, no default."""
174
187
        return self._get_user_option(option_name)
175
188
 
 
189
    def get_user_option_as_bool(self, option_name):
 
190
        """Get a generic option as a boolean - no special process, no default.
 
191
 
 
192
        :return None if the option doesn't exist or its value can't be
 
193
            interpreted as a boolean. Returns True or False otherwise.
 
194
        """
 
195
        s = self._get_user_option(option_name)
 
196
        if s is None:
 
197
            # The option doesn't exist
 
198
            return None
 
199
        val = ui.bool_from_string(s)
 
200
        if val is None:
 
201
            # The value can't be interpreted as a boolean
 
202
            trace.warning('Value "%s" is not a boolean for "%s"',
 
203
                          s, option_name)
 
204
        return val
 
205
 
 
206
    def get_user_option_as_list(self, option_name):
 
207
        """Get a generic option as a list - no special process, no default.
 
208
 
 
209
        :return None if the option doesn't exist. Returns the value as a list
 
210
            otherwise.
 
211
        """
 
212
        l = self._get_user_option(option_name)
 
213
        if isinstance(l, (str, unicode)):
 
214
            # A single value, most probably the user forgot the final ','
 
215
            l = [l]
 
216
        return l
 
217
 
176
218
    def gpg_signing_command(self):
177
219
        """What program should be used to sign signatures?"""
178
220
        result = self._gpg_signing_command()
195
237
        """See log_format()."""
196
238
        return None
197
239
 
198
 
    def __init__(self):
199
 
        super(Config, self).__init__()
200
 
 
201
240
    def post_commit(self):
202
241
        """An ordered list of python functions to call.
203
242
 
215
254
 
216
255
    def username(self):
217
256
        """Return email-style username.
218
 
    
 
257
 
219
258
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
220
 
        
 
259
 
221
260
        $BZR_EMAIL can be set to override this (as well as the
222
261
        deprecated $BZREMAIL), then
223
262
        the concrete policy type is checked, and finally
224
263
        $EMAIL is examined.
225
264
        If none is found, a reasonable default is (hopefully)
226
265
        created.
227
 
    
 
266
 
228
267
        TODO: Check it's reasonably well-formed.
229
268
        """
230
269
        v = os.environ.get('BZR_EMAIL')
294
333
                path = 'bzr'
295
334
            return path
296
335
 
 
336
    def suppress_warning(self, warning):
 
337
        """Should the warning be suppressed or emitted.
 
338
 
 
339
        :param warning: The name of the warning being tested.
 
340
 
 
341
        :returns: True if the warning should be suppressed, False otherwise.
 
342
        """
 
343
        warnings = self.get_user_option_as_list('suppress_warnings')
 
344
        if warnings is None or warning not in warnings:
 
345
            return False
 
346
        else:
 
347
            return True
 
348
 
297
349
 
298
350
class IniBasedConfig(Config):
299
351
    """A configuration policy that draws from ini files."""
300
352
 
 
353
    def __init__(self, get_filename):
 
354
        super(IniBasedConfig, self).__init__()
 
355
        self._get_filename = get_filename
 
356
        self._parser = None
 
357
 
301
358
    def _get_parser(self, file=None):
302
359
        if self._parser is not None:
303
360
            return self._parser
331
388
        """Return the policy for the given (section, option_name) pair."""
332
389
        return POLICY_NONE
333
390
 
 
391
    def _get_change_editor(self):
 
392
        return self.get_user_option('change_editor')
 
393
 
334
394
    def _get_signature_checking(self):
335
395
        """See Config._get_signature_checking."""
336
396
        policy = self._get_user_option('check_signatures')
380
440
        """See Config.log_format."""
381
441
        return self._get_user_option('log_format')
382
442
 
383
 
    def __init__(self, get_filename):
384
 
        super(IniBasedConfig, self).__init__()
385
 
        self._get_filename = get_filename
386
 
        self._parser = None
387
 
        
388
443
    def _post_commit(self):
389
444
        """See Config.post_commit."""
390
445
        return self._get_user_option('post_commit')
413
468
 
414
469
    def _get_alias(self, value):
415
470
        try:
416
 
            return self._get_parser().get_value("ALIASES", 
 
471
            return self._get_parser().get_value("ALIASES",
417
472
                                                value)
418
473
        except KeyError:
419
474
            pass
463
518
        self._write_config_file()
464
519
 
465
520
    def _write_config_file(self):
466
 
        f = open(self._get_filename(), 'wb')
 
521
        path = self._get_filename()
 
522
        f = open(path, 'wb')
 
523
        osutils.copy_ownership_from_path(path)
467
524
        self._get_parser().write(f)
468
525
        f.close()
469
526
 
641
698
 
642
699
    def _get_safe_value(self, option_name):
643
700
        """This variant of get_best_value never returns untrusted values.
644
 
        
 
701
 
645
702
        It does not return values from the branch data, because the branch may
646
703
        not be controlled by the user.
647
704
 
656
713
 
657
714
    def _get_user_id(self):
658
715
        """Return the full user id for the branch.
659
 
    
 
716
 
660
717
        e.g. "John Hacker <jhacker@example.com>"
661
718
        This is looked up in the email controlfile for the branch.
662
719
        """
666
723
                    .rstrip("\r\n"))
667
724
        except errors.NoSuchFile, e:
668
725
            pass
669
 
        
 
726
 
670
727
        return self._get_best_value('_get_user_id')
671
728
 
 
729
    def _get_change_editor(self):
 
730
        return self._get_best_value('_get_change_editor')
 
731
 
672
732
    def _get_signature_checking(self):
673
733
        """See Config._get_signature_checking."""
674
734
        return self._get_best_value('_get_signature_checking')
708
768
                        trace.warning('Value "%s" is masked by "%s" from'
709
769
                                      ' branch.conf', value, mask_value)
710
770
 
711
 
 
712
771
    def _gpg_signing_command(self):
713
772
        """See Config.gpg_signing_command."""
714
773
        return self._get_safe_value('_gpg_signing_command')
715
 
        
 
774
 
716
775
    def __init__(self, branch):
717
776
        super(BranchConfig, self).__init__()
718
777
        self._location_config = None
719
778
        self._branch_data_config = None
720
779
        self._global_config = None
721
780
        self.branch = branch
722
 
        self.option_sources = (self._get_location_config, 
 
781
        self.option_sources = (self._get_location_config,
723
782
                               self._get_branch_data_config,
724
783
                               self._get_global_config)
725
784
 
761
820
            os.mkdir(parent_dir)
762
821
        trace.mutter('creating config directory: %r', path)
763
822
        os.mkdir(path)
 
823
        osutils.copy_ownership_from_path(path)
764
824
 
765
825
 
766
826
def config_dir():
767
827
    """Return per-user configuration directory.
768
828
 
769
829
    By default this is ~/.bazaar/
770
 
    
 
830
 
771
831
    TODO: Global option --config-dir to override this.
772
832
    """
773
833
    base = os.environ.get('BZR_HOME', None)
812
872
    return osutils.pathjoin(config_dir(), 'ignore')
813
873
 
814
874
 
 
875
def crash_dir():
 
876
    """Return the directory name to store crash files.
 
877
 
 
878
    This doesn't implicitly create it.
 
879
 
 
880
    On Windows it's in the config directory; elsewhere it's /var/crash
 
881
    which may be monitored by apport.  It can be overridden by
 
882
    $APPORT_CRASH_DIR.
 
883
    """
 
884
    if sys.platform == 'win32':
 
885
        return osutils.pathjoin(config_dir(), 'Crash')
 
886
    else:
 
887
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
 
888
        # 2010-01-31
 
889
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
 
890
 
 
891
 
 
892
def xdg_cache_dir():
 
893
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
 
894
    # Possibly this should be different on Windows?
 
895
    e = os.environ.get('XDG_CACHE_DIR', None)
 
896
    if e:
 
897
        return e
 
898
    else:
 
899
        return os.path.expanduser('~/.cache')
 
900
 
 
901
 
815
902
def _auto_user_id():
816
903
    """Calculate automatic user identification.
817
904
 
897
984
def extract_email_address(e):
898
985
    """Return just the address part of an email string.
899
986
 
900
 
    That is just the user@domain part, nothing else. 
 
987
    That is just the user@domain part, nothing else.
901
988
    This part is required to contain only ascii characters.
902
989
    If it can't be extracted, raises an error.
903
990
 
916
1003
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
917
1004
 
918
1005
    def __init__(self, branch):
919
 
        # XXX: Really this should be asking the branch for its configuration
920
 
        # data, rather than relying on a Transport, so that it can work 
921
 
        # more cleanly with a RemoteBranch that has no transport.
922
 
        self._config = TransportConfig(branch._transport, 'branch.conf')
 
1006
        self._config = branch._get_config()
923
1007
        self.branch = branch
924
1008
 
925
1009
    def _get_parser(self, file=None):
933
1017
            return self._config.get_option(name, section, default)
934
1018
        finally:
935
1019
            self.branch.unlock()
936
 
        return result
937
1020
 
938
1021
    def set_option(self, value, name, section=None):
939
1022
        """Set a per-branch configuration option"""
992
1075
        section[option_name] = value
993
1076
        self._save()
994
1077
 
995
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None):
 
1078
    def get_credentials(self, scheme, host, port=None, user=None, path=None, 
 
1079
                        realm=None):
996
1080
        """Returns the matching credentials from authentication.conf file.
997
1081
 
998
1082
        :param scheme: protocol
1004
1088
        :param user: login (optional)
1005
1089
 
1006
1090
        :param path: the absolute path on the server (optional)
 
1091
        
 
1092
        :param realm: the http authentication realm (optional)
1007
1093
 
1008
1094
        :return: A dict containing the matching credentials or None.
1009
1095
           This includes:
1010
1096
           - name: the section name of the credentials in the
1011
1097
             authentication.conf file,
1012
 
           - user: can't de different from the provided user if any,
 
1098
           - user: can't be different from the provided user if any,
 
1099
           - scheme: the server protocol,
 
1100
           - host: the server address,
 
1101
           - port: the server port (can be None),
 
1102
           - path: the absolute server path (can be None),
 
1103
           - realm: the http specific authentication realm (can be None),
1013
1104
           - password: the decoded password, could be None if the credential
1014
1105
             defines only the user
1015
1106
           - verify_certificates: https specific, True if the server
1056
1147
            if a_user is None:
1057
1148
                # Can't find a user
1058
1149
                continue
 
1150
            # Prepare a credentials dictionary with additional keys
 
1151
            # for the credential providers
1059
1152
            credentials = dict(name=auth_def_name,
1060
1153
                               user=a_user,
 
1154
                               scheme=a_scheme,
 
1155
                               host=host,
 
1156
                               port=port,
 
1157
                               path=path,
 
1158
                               realm=realm,
1061
1159
                               password=auth_def.get('password', None),
1062
1160
                               verify_certificates=a_verify_certificates)
 
1161
            # Decode the password in the credentials (or get one)
1063
1162
            self.decode_password(credentials,
1064
1163
                                 auth_def.get('password_encoding', None))
1065
1164
            if 'auth' in debug.debug_flags:
1066
1165
                trace.mutter("Using authentication section: %r", auth_def_name)
1067
1166
            break
1068
1167
 
 
1168
        if credentials is None:
 
1169
            # No credentials were found in authentication.conf, try the fallback
 
1170
            # credentials stores.
 
1171
            credentials = credential_store_registry.get_fallback_credentials(
 
1172
                scheme, host, port, user, path, realm)
 
1173
 
1069
1174
        return credentials
1070
1175
 
1071
1176
    def set_credentials(self, name, host, user, scheme=None, password=None,
1072
 
                        port=None, path=None, verify_certificates=None):
 
1177
                        port=None, path=None, verify_certificates=None,
 
1178
                        realm=None):
1073
1179
        """Set authentication credentials for a host.
1074
1180
 
1075
1181
        Any existing credentials with matching scheme, host, port and path
1086
1192
            apply to.
1087
1193
        :param verify_certificates: On https, verify server certificates if
1088
1194
            True.
 
1195
        :param realm: The http authentication realm (optional).
1089
1196
        """
1090
1197
        values = {'host': host, 'user': user}
1091
1198
        if password is not None:
1098
1205
            values['path'] = path
1099
1206
        if verify_certificates is not None:
1100
1207
            values['verify_certificates'] = str(verify_certificates)
 
1208
        if realm is not None:
 
1209
            values['realm'] = realm
1101
1210
        config = self._get_config()
1102
1211
        for_deletion = []
1103
1212
        for section, existing_values in config.items():
1104
 
            for key in ('scheme', 'host', 'port', 'path'):
 
1213
            for key in ('scheme', 'host', 'port', 'path', 'realm'):
1105
1214
                if existing_values.get(key) != values.get(key):
1106
1215
                    break
1107
1216
            else:
1109
1218
        config.update({name: values})
1110
1219
        self._save()
1111
1220
 
1112
 
    def get_user(self, scheme, host, port=None,
1113
 
                 realm=None, path=None, prompt=None):
 
1221
    def get_user(self, scheme, host, port=None, realm=None, path=None,
 
1222
                 prompt=None, ask=False, default=None):
1114
1223
        """Get a user from authentication file.
1115
1224
 
1116
1225
        :param scheme: protocol
1123
1232
 
1124
1233
        :param path: the absolute path on the server (optional)
1125
1234
 
 
1235
        :param ask: Ask the user if there is no explicitly configured username 
 
1236
                    (optional)
 
1237
 
 
1238
        :param default: The username returned if none is defined (optional).
 
1239
 
1126
1240
        :return: The found user.
1127
1241
        """
1128
1242
        credentials = self.get_credentials(scheme, host, port, user=None,
1129
 
                                           path=path)
 
1243
                                           path=path, realm=realm)
1130
1244
        if credentials is not None:
1131
1245
            user = credentials['user']
1132
1246
        else:
1133
1247
            user = None
 
1248
        if user is None:
 
1249
            if ask:
 
1250
                if prompt is None:
 
1251
                    # Create a default prompt suitable for most cases
 
1252
                    prompt = scheme.upper() + ' %(host)s username'
 
1253
                # Special handling for optional fields in the prompt
 
1254
                if port is not None:
 
1255
                    prompt_host = '%s:%d' % (host, port)
 
1256
                else:
 
1257
                    prompt_host = host
 
1258
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
 
1259
            else:
 
1260
                user = default
1134
1261
        return user
1135
1262
 
1136
1263
    def get_password(self, scheme, host, user, port=None,
1151
1278
 
1152
1279
        :return: The found password or the one entered by the user.
1153
1280
        """
1154
 
        credentials = self.get_credentials(scheme, host, port, user, path)
 
1281
        credentials = self.get_credentials(scheme, host, port, user, path,
 
1282
                                           realm)
1155
1283
        if credentials is not None:
1156
1284
            password = credentials['password']
1157
1285
            if password is not None and scheme is 'ssh':
1176
1304
        return password
1177
1305
 
1178
1306
    def decode_password(self, credentials, encoding):
1179
 
        return credentials
 
1307
        try:
 
1308
            cs = credential_store_registry.get_credential_store(encoding)
 
1309
        except KeyError:
 
1310
            raise ValueError('%r is not a known password_encoding' % encoding)
 
1311
        credentials['password'] = cs.decode_password(credentials)
 
1312
        return credentials
 
1313
 
 
1314
 
 
1315
class CredentialStoreRegistry(registry.Registry):
 
1316
    """A class that registers credential stores.
 
1317
 
 
1318
    A credential store provides access to credentials via the password_encoding
 
1319
    field in authentication.conf sections.
 
1320
 
 
1321
    Except for stores provided by bzr itself, most stores are expected to be
 
1322
    provided by plugins that will therefore use
 
1323
    register_lazy(password_encoding, module_name, member_name, help=help,
 
1324
    fallback=fallback) to install themselves.
 
1325
 
 
1326
    A fallback credential store is one that is queried if no credentials can be
 
1327
    found via authentication.conf.
 
1328
    """
 
1329
 
 
1330
    def get_credential_store(self, encoding=None):
 
1331
        cs = self.get(encoding)
 
1332
        if callable(cs):
 
1333
            cs = cs()
 
1334
        return cs
 
1335
 
 
1336
    def is_fallback(self, name):
 
1337
        """Check if the named credentials store should be used as fallback."""
 
1338
        return self.get_info(name)
 
1339
 
 
1340
    def get_fallback_credentials(self, scheme, host, port=None, user=None,
 
1341
                                 path=None, realm=None):
 
1342
        """Request credentials from all fallback credentials stores.
 
1343
 
 
1344
        The first credentials store that can provide credentials wins.
 
1345
        """
 
1346
        credentials = None
 
1347
        for name in self.keys():
 
1348
            if not self.is_fallback(name):
 
1349
                continue
 
1350
            cs = self.get_credential_store(name)
 
1351
            credentials = cs.get_credentials(scheme, host, port, user,
 
1352
                                             path, realm)
 
1353
            if credentials is not None:
 
1354
                # We found some credentials
 
1355
                break
 
1356
        return credentials
 
1357
 
 
1358
    def register(self, key, obj, help=None, override_existing=False,
 
1359
                 fallback=False):
 
1360
        """Register a new object to a name.
 
1361
 
 
1362
        :param key: This is the key to use to request the object later.
 
1363
        :param obj: The object to register.
 
1364
        :param help: Help text for this entry. This may be a string or
 
1365
                a callable. If it is a callable, it should take two
 
1366
                parameters (registry, key): this registry and the key that
 
1367
                the help was registered under.
 
1368
        :param override_existing: Raise KeyErorr if False and something has
 
1369
                already been registered for that key. If True, ignore if there
 
1370
                is an existing key (always register the new value).
 
1371
        :param fallback: Whether this credential store should be 
 
1372
                used as fallback.
 
1373
        """
 
1374
        return super(CredentialStoreRegistry,
 
1375
                     self).register(key, obj, help, info=fallback,
 
1376
                                    override_existing=override_existing)
 
1377
 
 
1378
    def register_lazy(self, key, module_name, member_name,
 
1379
                      help=None, override_existing=False,
 
1380
                      fallback=False):
 
1381
        """Register a new credential store to be loaded on request.
 
1382
 
 
1383
        :param module_name: The python path to the module. Such as 'os.path'.
 
1384
        :param member_name: The member of the module to return.  If empty or
 
1385
                None, get() will return the module itself.
 
1386
        :param help: Help text for this entry. This may be a string or
 
1387
                a callable.
 
1388
        :param override_existing: If True, replace the existing object
 
1389
                with the new one. If False, if there is already something
 
1390
                registered with the same key, raise a KeyError
 
1391
        :param fallback: Whether this credential store should be 
 
1392
                used as fallback.
 
1393
        """
 
1394
        return super(CredentialStoreRegistry, self).register_lazy(
 
1395
            key, module_name, member_name, help,
 
1396
            info=fallback, override_existing=override_existing)
 
1397
 
 
1398
 
 
1399
credential_store_registry = CredentialStoreRegistry()
 
1400
 
 
1401
 
 
1402
class CredentialStore(object):
 
1403
    """An abstract class to implement storage for credentials"""
 
1404
 
 
1405
    def decode_password(self, credentials):
 
1406
        """Returns a clear text password for the provided credentials."""
 
1407
        raise NotImplementedError(self.decode_password)
 
1408
 
 
1409
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
 
1410
                        realm=None):
 
1411
        """Return the matching credentials from this credential store.
 
1412
 
 
1413
        This method is only called on fallback credential stores.
 
1414
        """
 
1415
        raise NotImplementedError(self.get_credentials)
 
1416
 
 
1417
 
 
1418
 
 
1419
class PlainTextCredentialStore(CredentialStore):
 
1420
    __doc__ = """Plain text credential store for the authentication.conf file"""
 
1421
 
 
1422
    def decode_password(self, credentials):
 
1423
        """See CredentialStore.decode_password."""
 
1424
        return credentials['password']
 
1425
 
 
1426
 
 
1427
credential_store_registry.register('plain', PlainTextCredentialStore,
 
1428
                                   help=PlainTextCredentialStore.__doc__)
 
1429
credential_store_registry.default_key = 'plain'
1180
1430
 
1181
1431
 
1182
1432
class BzrDirConfig(object):
1183
1433
 
1184
 
    def __init__(self, transport):
1185
 
        self._config = TransportConfig(transport, 'control.conf')
 
1434
    def __init__(self, bzrdir):
 
1435
        self._bzrdir = bzrdir
 
1436
        self._config = bzrdir._get_config()
1186
1437
 
1187
1438
    def set_default_stack_on(self, value):
1188
1439
        """Set the default stacking location.
1192
1443
        This policy affects all branches contained by this bzrdir, except for
1193
1444
        those under repositories.
1194
1445
        """
 
1446
        if self._config is None:
 
1447
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1195
1448
        if value is None:
1196
1449
            self._config.set_option('', 'default_stack_on')
1197
1450
        else:
1205
1458
        This policy affects all branches contained by this bzrdir, except for
1206
1459
        those under repositories.
1207
1460
        """
 
1461
        if self._config is None:
 
1462
            return None
1208
1463
        value = self._config.get_option('default_stack_on')
1209
1464
        if value == '':
1210
1465
            value = None
1255
1510
            configobj.setdefault(section, {})[name] = value
1256
1511
        self._set_configobj(configobj)
1257
1512
 
 
1513
    def _get_config_file(self):
 
1514
        try:
 
1515
            return StringIO(self._transport.get_bytes(self._filename))
 
1516
        except errors.NoSuchFile:
 
1517
            return StringIO()
 
1518
 
1258
1519
    def _get_configobj(self):
1259
 
        try:
1260
 
            return ConfigObj(self._transport.get(self._filename),
1261
 
                             encoding='utf-8')
1262
 
        except errors.NoSuchFile:
1263
 
            return ConfigObj(encoding='utf-8')
 
1520
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1264
1521
 
1265
1522
    def _set_configobj(self, configobj):
1266
1523
        out_file = StringIO()