~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Pool
  • Date: 2009-07-27 05:38:00 UTC
  • mto: This revision was merged to the branch mainline in revision 4587.
  • Revision ID: mbp@sourcefrog.net-20090727053800-bgnhmzzgo0u0314s
Remove tests for deleted LockableFiles methods

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2007, 2008 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
65
65
import os
66
66
import sys
67
67
 
68
 
from bzrlib.decorators import needs_write_lock
69
68
from bzrlib.lazy_import import lazy_import
70
69
lazy_import(globals(), """
71
70
import errno
75
74
 
76
75
import bzrlib
77
76
from bzrlib import (
78
 
    atomicfile,
79
77
    debug,
80
78
    errors,
81
 
    lockdir,
82
79
    mail_client,
83
80
    osutils,
84
81
    registry,
85
82
    symbol_versioning,
86
83
    trace,
87
 
    transport,
88
84
    ui,
89
85
    urlutils,
90
86
    win32utils,
157
153
        """Get the users pop up editor."""
158
154
        raise NotImplementedError
159
155
 
160
 
    def get_change_editor(self, old_tree, new_tree):
161
 
        from bzrlib import diff
162
 
        cmd = self._get_change_editor()
163
 
        if cmd is None:
164
 
            return None
165
 
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
166
 
                                             sys.stdout)
167
 
 
168
 
 
169
156
    def get_mail_client(self):
170
157
        """Get a mail client to use"""
171
158
        selected_client = self.get_user_option('mail_client')
194
181
        """Get a generic option as a boolean - no special process, no default.
195
182
 
196
183
        :return None if the option doesn't exist or its value can't be
197
 
            interpreted as a boolean. Returns True or False otherwise.
 
184
            interpreted as a boolean. Returns True or False ortherwise.
198
185
        """
199
186
        s = self._get_user_option(option_name)
200
 
        if s is None:
201
 
            # The option doesn't exist
202
 
            return None
203
 
        val = ui.bool_from_string(s)
204
 
        if val is None:
205
 
            # The value can't be interpreted as a boolean
206
 
            trace.warning('Value "%s" is not a boolean for "%s"',
207
 
                          s, option_name)
208
 
        return val
209
 
 
210
 
    def get_user_option_as_list(self, option_name):
211
 
        """Get a generic option as a list - no special process, no default.
212
 
 
213
 
        :return None if the option doesn't exist. Returns the value as a list
214
 
            otherwise.
215
 
        """
216
 
        l = self._get_user_option(option_name)
217
 
        if isinstance(l, (str, unicode)):
218
 
            # A single value, most probably the user forgot the final ','
219
 
            l = [l]
220
 
        return l
 
187
        return ui.bool_from_string(s)
221
188
 
222
189
    def gpg_signing_command(self):
223
190
        """What program should be used to sign signatures?"""
261
228
 
262
229
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
263
230
 
264
 
        $BZR_EMAIL can be set to override this, then
 
231
        $BZR_EMAIL can be set to override this (as well as the
 
232
        deprecated $BZREMAIL), then
265
233
        the concrete policy type is checked, and finally
266
234
        $EMAIL is examined.
267
 
        If no username can be found, errors.NoWhoami exception is raised.
 
235
        If none is found, a reasonable default is (hopefully)
 
236
        created.
268
237
 
269
238
        TODO: Check it's reasonably well-formed.
270
239
        """
280
249
        if v:
281
250
            return v.decode(osutils.get_user_encoding())
282
251
 
283
 
        raise errors.NoWhoami()
284
 
 
285
 
    def ensure_username(self):
286
 
        """Raise errors.NoWhoami if username is not set.
287
 
 
288
 
        This method relies on the username() function raising the error.
289
 
        """
290
 
        self.username()
 
252
        name, email = _auto_user_id()
 
253
        if name:
 
254
            return '%s <%s>' % (name, email)
 
255
        else:
 
256
            return email
291
257
 
292
258
    def signature_checking(self):
293
259
        """What is the current policy for signature checking?."""
338
304
                path = 'bzr'
339
305
            return path
340
306
 
341
 
    def suppress_warning(self, warning):
342
 
        """Should the warning be suppressed or emitted.
343
 
 
344
 
        :param warning: The name of the warning being tested.
345
 
 
346
 
        :returns: True if the warning should be suppressed, False otherwise.
347
 
        """
348
 
        warnings = self.get_user_option_as_list('suppress_warnings')
349
 
        if warnings is None or warning not in warnings:
350
 
            return False
351
 
        else:
352
 
            return True
353
 
 
354
307
 
355
308
class IniBasedConfig(Config):
356
309
    """A configuration policy that draws from ini files."""
357
310
 
358
 
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
359
 
                 file_name=None):
360
 
        """Base class for configuration files using an ini-like syntax.
361
 
 
362
 
        :param file_name: The configuration file path.
363
 
        """
 
311
    def __init__(self, get_filename):
364
312
        super(IniBasedConfig, self).__init__()
365
 
        self.file_name = file_name
366
 
        if symbol_versioning.deprecated_passed(get_filename):
367
 
            symbol_versioning.warn(
368
 
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
369
 
                ' Use file_name instead.',
370
 
                DeprecationWarning,
371
 
                stacklevel=2)
372
 
            if get_filename is not None:
373
 
                self.file_name = get_filename()
374
 
        else:
375
 
            self.file_name = file_name
376
 
        self._content = None
 
313
        self._get_filename = get_filename
377
314
        self._parser = None
378
315
 
379
 
    @classmethod
380
 
    def from_string(cls, str_or_unicode, file_name=None, save=False):
381
 
        """Create a config object from a string.
382
 
 
383
 
        :param str_or_unicode: A string representing the file content. This will
384
 
            be utf-8 encoded.
385
 
 
386
 
        :param file_name: The configuration file path.
387
 
 
388
 
        :param _save: Whether the file should be saved upon creation.
389
 
        """
390
 
        conf = cls(file_name=file_name)
391
 
        conf._create_from_string(str_or_unicode, save)
392
 
        return conf
393
 
 
394
 
    def _create_from_string(self, str_or_unicode, save):
395
 
        self._content = StringIO(str_or_unicode.encode('utf-8'))
396
 
        # Some tests use in-memory configs, some other always need the config
397
 
        # file to exist on disk.
398
 
        if save:
399
 
            self._write_config_file()
400
 
 
401
 
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
 
316
    def _get_parser(self, file=None):
402
317
        if self._parser is not None:
403
318
            return self._parser
404
 
        if symbol_versioning.deprecated_passed(file):
405
 
            symbol_versioning.warn(
406
 
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
407
 
                ' Use IniBasedConfig(_content=xxx) instead.',
408
 
                DeprecationWarning,
409
 
                stacklevel=2)
410
 
        if self._content is not None:
411
 
            co_input = self._content
412
 
        elif self.file_name is None:
413
 
            raise AssertionError('We have no content to create the config')
 
319
        if file is None:
 
320
            input = self._get_filename()
414
321
        else:
415
 
            co_input = self.file_name
 
322
            input = file
416
323
        try:
417
 
            self._parser = ConfigObj(co_input, encoding='utf-8')
 
324
            self._parser = ConfigObj(input, encoding='utf-8')
418
325
        except configobj.ConfigObjError, e:
419
326
            raise errors.ParseConfigError(e.errors, e.config.filename)
420
 
        # Make sure self.reload() will use the right file name
421
 
        self._parser.filename = self.file_name
422
327
        return self._parser
423
328
 
424
 
    def reload(self):
425
 
        """Reload the config file from disk."""
426
 
        if self.file_name is None:
427
 
            raise AssertionError('We need a file name to reload the config')
428
 
        if self._parser is not None:
429
 
            self._parser.reload()
430
 
 
431
329
    def _get_matching_sections(self):
432
330
        """Return an ordered list of (section_name, extra_path) pairs.
433
331
 
448
346
        """Return the policy for the given (section, option_name) pair."""
449
347
        return POLICY_NONE
450
348
 
451
 
    def _get_change_editor(self):
452
 
        return self.get_user_option('change_editor')
453
 
 
454
349
    def _get_signature_checking(self):
455
350
        """See Config._get_signature_checking."""
456
351
        policy = self._get_user_option('check_signatures')
536
431
    def _get_nickname(self):
537
432
        return self.get_user_option('nickname')
538
433
 
539
 
    def _write_config_file(self):
540
 
        if self.file_name is None:
541
 
            raise AssertionError('We cannot save, self.file_name is None')
542
 
        conf_dir = os.path.dirname(self.file_name)
543
 
        ensure_config_dir_exists(conf_dir)
544
 
        atomic_file = atomicfile.AtomicFile(self.file_name)
545
 
        self._get_parser().write(atomic_file)
546
 
        atomic_file.commit()
547
 
        atomic_file.close()
548
 
        osutils.copy_ownership_from_path(self.file_name)
549
 
 
550
 
 
551
 
class LockableConfig(IniBasedConfig):
552
 
    """A configuration needing explicit locking for access.
553
 
 
554
 
    If several processes try to write the config file, the accesses need to be
555
 
    serialized.
556
 
 
557
 
    Daughter classes should decorate all methods that update a config with the
558
 
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
559
 
    ``_write_config_file()`` method. These methods (typically ``set_option()``
560
 
    and variants must reload the config file from disk before calling
561
 
    ``_write_config_file()``), this can be achieved by calling the
562
 
    ``self.reload()`` method. Note that the lock scope should cover both the
563
 
    reading and the writing of the config file which is why the decorator can't
564
 
    be applied to ``_write_config_file()`` only.
565
 
 
566
 
    This should be enough to implement the following logic:
567
 
    - lock for exclusive write access,
568
 
    - reload the config file from disk,
569
 
    - set the new value
570
 
    - unlock
571
 
 
572
 
    This logic guarantees that a writer can update a value without erasing an
573
 
    update made by another writer.
574
 
    """
575
 
 
576
 
    lock_name = 'lock'
577
 
 
578
 
    def __init__(self, file_name):
579
 
        super(LockableConfig, self).__init__(file_name=file_name)
580
 
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
581
 
        self.transport = transport.get_transport(self.dir)
582
 
        self._lock = lockdir.LockDir(self.transport, 'lock')
583
 
 
584
 
    def _create_from_string(self, unicode_bytes, save):
585
 
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
586
 
        if save:
587
 
            # We need to handle the saving here (as opposed to IniBasedConfig)
588
 
            # to be able to lock
589
 
            self.lock_write()
590
 
            self._write_config_file()
591
 
            self.unlock()
592
 
 
593
 
    def lock_write(self, token=None):
594
 
        """Takes a write lock in the directory containing the config file.
595
 
 
596
 
        If the directory doesn't exist it is created.
597
 
        """
598
 
        ensure_config_dir_exists(self.dir)
599
 
        return self._lock.lock_write(token)
600
 
 
601
 
    def unlock(self):
602
 
        self._lock.unlock()
603
 
 
604
 
    def break_lock(self):
605
 
        self._lock.break_lock()
606
 
 
607
 
    def _write_config_file(self):
608
 
        if self._lock is None or not self._lock.is_held:
609
 
            # NB: if the following exception is raised it probably means a
610
 
            # missing @needs_write_lock decorator on one of the callers.
611
 
            raise errors.ObjectNotLocked(self)
612
 
        super(LockableConfig, self)._write_config_file()
613
 
 
614
 
 
615
 
class GlobalConfig(LockableConfig):
 
434
 
 
435
class GlobalConfig(IniBasedConfig):
616
436
    """The configuration that should be used for a specific location."""
617
437
 
618
 
    def __init__(self):
619
 
        super(GlobalConfig, self).__init__(file_name=config_filename())
620
 
 
621
 
    @classmethod
622
 
    def from_string(cls, str_or_unicode, save=False):
623
 
        """Create a config object from a string.
624
 
 
625
 
        :param str_or_unicode: A string representing the file content. This
626
 
            will be utf-8 encoded.
627
 
 
628
 
        :param save: Whether the file should be saved upon creation.
629
 
        """
630
 
        conf = cls()
631
 
        conf._create_from_string(str_or_unicode, save)
632
 
        return conf
633
 
 
634
438
    def get_editor(self):
635
439
        return self._get_user_option('editor')
636
440
 
637
 
    @needs_write_lock
 
441
    def __init__(self):
 
442
        super(GlobalConfig, self).__init__(config_filename)
 
443
 
638
444
    def set_user_option(self, option, value):
639
445
        """Save option and its value in the configuration."""
640
446
        self._set_option(option, value, 'DEFAULT')
646
452
        else:
647
453
            return {}
648
454
 
649
 
    @needs_write_lock
650
455
    def set_alias(self, alias_name, alias_command):
651
456
        """Save the alias in the configuration."""
652
457
        self._set_option(alias_name, alias_command, 'ALIASES')
653
458
 
654
 
    @needs_write_lock
655
459
    def unset_alias(self, alias_name):
656
460
        """Unset an existing alias."""
657
 
        self.reload()
658
461
        aliases = self._get_parser().get('ALIASES')
659
462
        if not aliases or alias_name not in aliases:
660
463
            raise errors.NoSuchAlias(alias_name)
662
465
        self._write_config_file()
663
466
 
664
467
    def _set_option(self, option, value, section):
665
 
        self.reload()
 
468
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
469
        # file lock on bazaar.conf.
 
470
        conf_dir = os.path.dirname(self._get_filename())
 
471
        ensure_config_dir_exists(conf_dir)
666
472
        self._get_parser().setdefault(section, {})[option] = value
667
473
        self._write_config_file()
668
474
 
669
 
 
670
 
class LocationConfig(LockableConfig):
 
475
    def _write_config_file(self):
 
476
        f = open(self._get_filename(), 'wb')
 
477
        self._get_parser().write(f)
 
478
        f.close()
 
479
 
 
480
 
 
481
class LocationConfig(IniBasedConfig):
671
482
    """A configuration object that gives the policy for a location."""
672
483
 
673
484
    def __init__(self, location):
674
 
        super(LocationConfig, self).__init__(
675
 
            file_name=locations_config_filename())
 
485
        name_generator = locations_config_filename
 
486
        if (not os.path.exists(name_generator()) and
 
487
                os.path.exists(branches_config_filename())):
 
488
            if sys.platform == 'win32':
 
489
                trace.warning('Please rename %s to %s'
 
490
                              % (branches_config_filename(),
 
491
                                 locations_config_filename()))
 
492
            else:
 
493
                trace.warning('Please rename ~/.bazaar/branches.conf'
 
494
                              ' to ~/.bazaar/locations.conf')
 
495
            name_generator = branches_config_filename
 
496
        super(LocationConfig, self).__init__(name_generator)
676
497
        # local file locations are looked up by local path, rather than
677
498
        # by file url. This is because the config file is a user
678
499
        # file, and we would rather not expose the user to file urls.
680
501
            location = urlutils.local_path_from_url(location)
681
502
        self.location = location
682
503
 
683
 
    @classmethod
684
 
    def from_string(cls, str_or_unicode, location, save=False):
685
 
        """Create a config object from a string.
686
 
 
687
 
        :param str_or_unicode: A string representing the file content. This will
688
 
            be utf-8 encoded.
689
 
 
690
 
        :param location: The location url to filter the configuration.
691
 
 
692
 
        :param save: Whether the file should be saved upon creation.
693
 
        """
694
 
        conf = cls(location)
695
 
        conf._create_from_string(str_or_unicode, save)
696
 
        return conf
697
 
 
698
504
    def _get_matching_sections(self):
699
505
        """Return an ordered list of section names matching this location."""
700
506
        sections = self._get_parser()
788
594
            if policy_key in self._get_parser()[section]:
789
595
                del self._get_parser()[section][policy_key]
790
596
 
791
 
    @needs_write_lock
792
597
    def set_user_option(self, option, value, store=STORE_LOCATION):
793
598
        """Save option and its value in the configuration."""
794
599
        if store not in [STORE_LOCATION,
796
601
                         STORE_LOCATION_APPENDPATH]:
797
602
            raise ValueError('bad storage policy %r for %r' %
798
603
                (store, option))
799
 
        self.reload()
 
604
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
605
        # file lock on locations.conf.
 
606
        conf_dir = os.path.dirname(self._get_filename())
 
607
        ensure_config_dir_exists(conf_dir)
800
608
        location = self.location
801
609
        if location.endswith('/'):
802
610
            location = location[:-1]
803
 
        parser = self._get_parser()
804
 
        if not location in parser and not location + '/' in parser:
805
 
            parser[location] = {}
806
 
        elif location + '/' in parser:
 
611
        if (not location in self._get_parser() and
 
612
            not location + '/' in self._get_parser()):
 
613
            self._get_parser()[location]={}
 
614
        elif location + '/' in self._get_parser():
807
615
            location = location + '/'
808
 
        parser[location][option]=value
 
616
        self._get_parser()[location][option]=value
809
617
        # the allowed values of store match the config policies
810
618
        self._set_option_policy(location, option, store)
811
 
        self._write_config_file()
 
619
        self._get_parser().write(file(self._get_filename(), 'wb'))
812
620
 
813
621
 
814
622
class BranchConfig(Config):
815
623
    """A configuration object giving the policy for a branch."""
816
624
 
817
 
    def __init__(self, branch):
818
 
        super(BranchConfig, self).__init__()
819
 
        self._location_config = None
820
 
        self._branch_data_config = None
821
 
        self._global_config = None
822
 
        self.branch = branch
823
 
        self.option_sources = (self._get_location_config,
824
 
                               self._get_branch_data_config,
825
 
                               self._get_global_config)
826
 
 
827
625
    def _get_branch_data_config(self):
828
626
        if self._branch_data_config is None:
829
627
            self._branch_data_config = TreeConfig(self.branch)
881
679
 
882
680
        return self._get_best_value('_get_user_id')
883
681
 
884
 
    def _get_change_editor(self):
885
 
        return self._get_best_value('_get_change_editor')
886
 
 
887
682
    def _get_signature_checking(self):
888
683
        """See Config._get_signature_checking."""
889
684
        return self._get_best_value('_get_signature_checking')
927
722
        """See Config.gpg_signing_command."""
928
723
        return self._get_safe_value('_gpg_signing_command')
929
724
 
 
725
    def __init__(self, branch):
 
726
        super(BranchConfig, self).__init__()
 
727
        self._location_config = None
 
728
        self._branch_data_config = None
 
729
        self._global_config = None
 
730
        self.branch = branch
 
731
        self.option_sources = (self._get_location_config,
 
732
                               self._get_branch_data_config,
 
733
                               self._get_global_config)
 
734
 
930
735
    def _post_commit(self):
931
736
        """See Config.post_commit."""
932
737
        return self._get_safe_value('_post_commit')
965
770
            os.mkdir(parent_dir)
966
771
        trace.mutter('creating config directory: %r', path)
967
772
        os.mkdir(path)
968
 
        osutils.copy_ownership_from_path(path)
969
773
 
970
774
 
971
775
def config_dir():
986
790
                                  ' or HOME set')
987
791
        return osutils.pathjoin(base, 'bazaar', '2.0')
988
792
    else:
 
793
        # cygwin, linux, and darwin all have a $HOME directory
989
794
        if base is None:
990
795
            base = os.path.expanduser("~")
991
796
        return osutils.pathjoin(base, ".bazaar")
996
801
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
997
802
 
998
803
 
 
804
def branches_config_filename():
 
805
    """Return per-user configuration ini file filename."""
 
806
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
807
 
 
808
 
999
809
def locations_config_filename():
1000
810
    """Return per-user configuration ini file filename."""
1001
811
    return osutils.pathjoin(config_dir(), 'locations.conf')
1011
821
    return osutils.pathjoin(config_dir(), 'ignore')
1012
822
 
1013
823
 
1014
 
def crash_dir():
1015
 
    """Return the directory name to store crash files.
1016
 
 
1017
 
    This doesn't implicitly create it.
1018
 
 
1019
 
    On Windows it's in the config directory; elsewhere it's /var/crash
1020
 
    which may be monitored by apport.  It can be overridden by
1021
 
    $APPORT_CRASH_DIR.
 
824
def _auto_user_id():
 
825
    """Calculate automatic user identification.
 
826
 
 
827
    Returns (realname, email).
 
828
 
 
829
    Only used when none is set in the environment or the id file.
 
830
 
 
831
    This previously used the FQDN as the default domain, but that can
 
832
    be very slow on machines where DNS is broken.  So now we simply
 
833
    use the hostname.
1022
834
    """
 
835
    import socket
 
836
 
1023
837
    if sys.platform == 'win32':
1024
 
        return osutils.pathjoin(config_dir(), 'Crash')
1025
 
    else:
1026
 
        # XXX: hardcoded in apport_python_hook.py; therefore here too -- mbp
1027
 
        # 2010-01-31
1028
 
        return os.environ.get('APPORT_CRASH_DIR', '/var/crash')
1029
 
 
1030
 
 
1031
 
def xdg_cache_dir():
1032
 
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1033
 
    # Possibly this should be different on Windows?
1034
 
    e = os.environ.get('XDG_CACHE_DIR', None)
1035
 
    if e:
1036
 
        return e
1037
 
    else:
1038
 
        return os.path.expanduser('~/.cache')
 
838
        name = win32utils.get_user_name_unicode()
 
839
        if name is None:
 
840
            raise errors.BzrError("Cannot autodetect user name.\n"
 
841
                                  "Please, set your name with command like:\n"
 
842
                                  'bzr whoami "Your Name <name@domain.com>"')
 
843
        host = win32utils.get_host_name_unicode()
 
844
        if host is None:
 
845
            host = socket.gethostname()
 
846
        return name, (name + '@' + host)
 
847
 
 
848
    try:
 
849
        import pwd
 
850
        uid = os.getuid()
 
851
        try:
 
852
            w = pwd.getpwuid(uid)
 
853
        except KeyError:
 
854
            raise errors.BzrCommandError('Unable to determine your name.  '
 
855
                'Please use "bzr whoami" to set it.')
 
856
 
 
857
        # we try utf-8 first, because on many variants (like Linux),
 
858
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
859
        # false positives.  (many users will have their user encoding set to
 
860
        # latin-1, which cannot raise UnicodeError.)
 
861
        try:
 
862
            gecos = w.pw_gecos.decode('utf-8')
 
863
            encoding = 'utf-8'
 
864
        except UnicodeError:
 
865
            try:
 
866
                encoding = osutils.get_user_encoding()
 
867
                gecos = w.pw_gecos.decode(encoding)
 
868
            except UnicodeError:
 
869
                raise errors.BzrCommandError('Unable to determine your name.  '
 
870
                   'Use "bzr whoami" to set it.')
 
871
        try:
 
872
            username = w.pw_name.decode(encoding)
 
873
        except UnicodeError:
 
874
            raise errors.BzrCommandError('Unable to determine your name.  '
 
875
                'Use "bzr whoami" to set it.')
 
876
 
 
877
        comma = gecos.find(',')
 
878
        if comma == -1:
 
879
            realname = gecos
 
880
        else:
 
881
            realname = gecos[:comma]
 
882
        if not realname:
 
883
            realname = username
 
884
 
 
885
    except ImportError:
 
886
        import getpass
 
887
        try:
 
888
            user_encoding = osutils.get_user_encoding()
 
889
            realname = username = getpass.getuser().decode(user_encoding)
 
890
        except UnicodeDecodeError:
 
891
            raise errors.BzrError("Can't decode username as %s." % \
 
892
                    user_encoding)
 
893
 
 
894
    return realname, (username + '@' + socket.gethostname())
1039
895
 
1040
896
 
1041
897
def parse_username(username):
1129
985
        """Save the config file, only tests should use it for now."""
1130
986
        conf_dir = os.path.dirname(self._filename)
1131
987
        ensure_config_dir_exists(conf_dir)
1132
 
        f = file(self._filename, 'wb')
1133
 
        try:
1134
 
            self._get_config().write(f)
1135
 
        finally:
1136
 
            f.close()
 
988
        self._get_config().write(file(self._filename, 'wb'))
1137
989
 
1138
990
    def _set_option(self, section_name, option_name, value):
1139
991
        """Set an authentication configuration option"""
1487
1339
 
1488
1340
 
1489
1341
class PlainTextCredentialStore(CredentialStore):
1490
 
    __doc__ = """Plain text credential store for the authentication.conf file"""
 
1342
    """Plain text credential store for the authentication.conf file."""
1491
1343
 
1492
1344
    def decode_password(self, credentials):
1493
1345
        """See CredentialStore.decode_password."""
1582
1434
 
1583
1435
    def _get_config_file(self):
1584
1436
        try:
1585
 
            return StringIO(self._transport.get_bytes(self._filename))
 
1437
            return self._transport.get(self._filename)
1586
1438
        except errors.NoSuchFile:
1587
1439
            return StringIO()
1588
1440
 
1589
1441
    def _get_configobj(self):
1590
 
        f = self._get_config_file()
1591
 
        try:
1592
 
            return ConfigObj(f, encoding='utf-8')
1593
 
        finally:
1594
 
            f.close()
 
1442
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1595
1443
 
1596
1444
    def _set_configobj(self, configobj):
1597
1445
        out_file = StringIO()