~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: John Arbash Meinel
  • Date: 2009-06-19 17:53:37 UTC
  • mto: This revision was merged to the branch mainline in revision 4466.
  • Revision ID: john@arbash-meinel.com-20090619175337-uozt3bntdd48lh4z
Update time_graph to use X:1 ratios rather than 0.xxx ratios.
It is just easier to track now that the new code is much faster.

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,
150
146
class Config(object):
151
147
    """A configuration policy - what username, editor, gpg needs etc."""
152
148
 
153
 
    def __init__(self):
154
 
        super(Config, self).__init__()
155
 
 
156
149
    def get_editor(self):
157
150
        """Get the users pop up editor."""
158
151
        raise NotImplementedError
159
152
 
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
153
    def get_mail_client(self):
170
154
        """Get a mail client to use"""
171
155
        selected_client = self.get_user_option('mail_client')
190
174
        """Get a generic option - no special process, no default."""
191
175
        return self._get_user_option(option_name)
192
176
 
193
 
    def get_user_option_as_bool(self, option_name):
194
 
        """Get a generic option as a boolean - no special process, no default.
195
 
 
196
 
        :return None if the option doesn't exist or its value can't be
197
 
            interpreted as a boolean. Returns True or False otherwise.
198
 
        """
199
 
        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
221
 
 
222
177
    def gpg_signing_command(self):
223
178
        """What program should be used to sign signatures?"""
224
179
        result = self._gpg_signing_command()
241
196
        """See log_format()."""
242
197
        return None
243
198
 
 
199
    def __init__(self):
 
200
        super(Config, self).__init__()
 
201
 
244
202
    def post_commit(self):
245
203
        """An ordered list of python functions to call.
246
204
 
261
219
 
262
220
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
263
221
 
264
 
        $BZR_EMAIL can be set to override this, then
 
222
        $BZR_EMAIL can be set to override this (as well as the
 
223
        deprecated $BZREMAIL), then
265
224
        the concrete policy type is checked, and finally
266
225
        $EMAIL is examined.
267
 
        If no username can be found, errors.NoWhoami exception is raised.
 
226
        If none is found, a reasonable default is (hopefully)
 
227
        created.
268
228
 
269
229
        TODO: Check it's reasonably well-formed.
270
230
        """
280
240
        if v:
281
241
            return v.decode(osutils.get_user_encoding())
282
242
 
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()
 
243
        name, email = _auto_user_id()
 
244
        if name:
 
245
            return '%s <%s>' % (name, email)
 
246
        else:
 
247
            return email
291
248
 
292
249
    def signature_checking(self):
293
250
        """What is the current policy for signature checking?."""
338
295
                path = 'bzr'
339
296
            return path
340
297
 
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
298
 
355
299
class IniBasedConfig(Config):
356
300
    """A configuration policy that draws from ini files."""
357
301
 
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
 
        """
364
 
        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
377
 
        self._parser = None
378
 
 
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):
 
302
    def _get_parser(self, file=None):
402
303
        if self._parser is not None:
403
304
            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')
 
305
        if file is None:
 
306
            input = self._get_filename()
414
307
        else:
415
 
            co_input = self.file_name
 
308
            input = file
416
309
        try:
417
 
            self._parser = ConfigObj(co_input, encoding='utf-8')
 
310
            self._parser = ConfigObj(input, encoding='utf-8')
418
311
        except configobj.ConfigObjError, e:
419
312
            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
313
        return self._parser
423
314
 
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
315
    def _get_matching_sections(self):
432
316
        """Return an ordered list of (section_name, extra_path) pairs.
433
317
 
448
332
        """Return the policy for the given (section, option_name) pair."""
449
333
        return POLICY_NONE
450
334
 
451
 
    def _get_change_editor(self):
452
 
        return self.get_user_option('change_editor')
453
 
 
454
335
    def _get_signature_checking(self):
455
336
        """See Config._get_signature_checking."""
456
337
        policy = self._get_user_option('check_signatures')
500
381
        """See Config.log_format."""
501
382
        return self._get_user_option('log_format')
502
383
 
 
384
    def __init__(self, get_filename):
 
385
        super(IniBasedConfig, self).__init__()
 
386
        self._get_filename = get_filename
 
387
        self._parser = None
 
388
 
503
389
    def _post_commit(self):
504
390
        """See Config.post_commit."""
505
391
        return self._get_user_option('post_commit')
536
422
    def _get_nickname(self):
537
423
        return self.get_user_option('nickname')
538
424
 
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):
 
425
 
 
426
class GlobalConfig(IniBasedConfig):
616
427
    """The configuration that should be used for a specific location."""
617
428
 
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
429
    def get_editor(self):
635
430
        return self._get_user_option('editor')
636
431
 
637
 
    @needs_write_lock
 
432
    def __init__(self):
 
433
        super(GlobalConfig, self).__init__(config_filename)
 
434
 
638
435
    def set_user_option(self, option, value):
639
436
        """Save option and its value in the configuration."""
640
437
        self._set_option(option, value, 'DEFAULT')
646
443
        else:
647
444
            return {}
648
445
 
649
 
    @needs_write_lock
650
446
    def set_alias(self, alias_name, alias_command):
651
447
        """Save the alias in the configuration."""
652
448
        self._set_option(alias_name, alias_command, 'ALIASES')
653
449
 
654
 
    @needs_write_lock
655
450
    def unset_alias(self, alias_name):
656
451
        """Unset an existing alias."""
657
 
        self.reload()
658
452
        aliases = self._get_parser().get('ALIASES')
659
453
        if not aliases or alias_name not in aliases:
660
454
            raise errors.NoSuchAlias(alias_name)
662
456
        self._write_config_file()
663
457
 
664
458
    def _set_option(self, option, value, section):
665
 
        self.reload()
 
459
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
460
        # file lock on bazaar.conf.
 
461
        conf_dir = os.path.dirname(self._get_filename())
 
462
        ensure_config_dir_exists(conf_dir)
666
463
        self._get_parser().setdefault(section, {})[option] = value
667
464
        self._write_config_file()
668
465
 
669
 
 
670
 
class LocationConfig(LockableConfig):
 
466
    def _write_config_file(self):
 
467
        f = open(self._get_filename(), 'wb')
 
468
        self._get_parser().write(f)
 
469
        f.close()
 
470
 
 
471
 
 
472
class LocationConfig(IniBasedConfig):
671
473
    """A configuration object that gives the policy for a location."""
672
474
 
673
475
    def __init__(self, location):
674
 
        super(LocationConfig, self).__init__(
675
 
            file_name=locations_config_filename())
 
476
        name_generator = locations_config_filename
 
477
        if (not os.path.exists(name_generator()) and
 
478
                os.path.exists(branches_config_filename())):
 
479
            if sys.platform == 'win32':
 
480
                trace.warning('Please rename %s to %s'
 
481
                              % (branches_config_filename(),
 
482
                                 locations_config_filename()))
 
483
            else:
 
484
                trace.warning('Please rename ~/.bazaar/branches.conf'
 
485
                              ' to ~/.bazaar/locations.conf')
 
486
            name_generator = branches_config_filename
 
487
        super(LocationConfig, self).__init__(name_generator)
676
488
        # local file locations are looked up by local path, rather than
677
489
        # by file url. This is because the config file is a user
678
490
        # file, and we would rather not expose the user to file urls.
680
492
            location = urlutils.local_path_from_url(location)
681
493
        self.location = location
682
494
 
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
495
    def _get_matching_sections(self):
699
496
        """Return an ordered list of section names matching this location."""
700
497
        sections = self._get_parser()
788
585
            if policy_key in self._get_parser()[section]:
789
586
                del self._get_parser()[section][policy_key]
790
587
 
791
 
    @needs_write_lock
792
588
    def set_user_option(self, option, value, store=STORE_LOCATION):
793
589
        """Save option and its value in the configuration."""
794
590
        if store not in [STORE_LOCATION,
796
592
                         STORE_LOCATION_APPENDPATH]:
797
593
            raise ValueError('bad storage policy %r for %r' %
798
594
                (store, option))
799
 
        self.reload()
 
595
        # FIXME: RBC 20051029 This should refresh the parser and also take a
 
596
        # file lock on locations.conf.
 
597
        conf_dir = os.path.dirname(self._get_filename())
 
598
        ensure_config_dir_exists(conf_dir)
800
599
        location = self.location
801
600
        if location.endswith('/'):
802
601
            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:
 
602
        if (not location in self._get_parser() and
 
603
            not location + '/' in self._get_parser()):
 
604
            self._get_parser()[location]={}
 
605
        elif location + '/' in self._get_parser():
807
606
            location = location + '/'
808
 
        parser[location][option]=value
 
607
        self._get_parser()[location][option]=value
809
608
        # the allowed values of store match the config policies
810
609
        self._set_option_policy(location, option, store)
811
 
        self._write_config_file()
 
610
        self._get_parser().write(file(self._get_filename(), 'wb'))
812
611
 
813
612
 
814
613
class BranchConfig(Config):
815
614
    """A configuration object giving the policy for a branch."""
816
615
 
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
616
    def _get_branch_data_config(self):
828
617
        if self._branch_data_config is None:
829
618
            self._branch_data_config = TreeConfig(self.branch)
881
670
 
882
671
        return self._get_best_value('_get_user_id')
883
672
 
884
 
    def _get_change_editor(self):
885
 
        return self._get_best_value('_get_change_editor')
886
 
 
887
673
    def _get_signature_checking(self):
888
674
        """See Config._get_signature_checking."""
889
675
        return self._get_best_value('_get_signature_checking')
927
713
        """See Config.gpg_signing_command."""
928
714
        return self._get_safe_value('_gpg_signing_command')
929
715
 
 
716
    def __init__(self, branch):
 
717
        super(BranchConfig, self).__init__()
 
718
        self._location_config = None
 
719
        self._branch_data_config = None
 
720
        self._global_config = None
 
721
        self.branch = branch
 
722
        self.option_sources = (self._get_location_config,
 
723
                               self._get_branch_data_config,
 
724
                               self._get_global_config)
 
725
 
930
726
    def _post_commit(self):
931
727
        """See Config.post_commit."""
932
728
        return self._get_safe_value('_post_commit')
965
761
            os.mkdir(parent_dir)
966
762
        trace.mutter('creating config directory: %r', path)
967
763
        os.mkdir(path)
968
 
        osutils.copy_ownership_from_path(path)
969
764
 
970
765
 
971
766
def config_dir():
986
781
                                  ' or HOME set')
987
782
        return osutils.pathjoin(base, 'bazaar', '2.0')
988
783
    else:
 
784
        # cygwin, linux, and darwin all have a $HOME directory
989
785
        if base is None:
990
786
            base = os.path.expanduser("~")
991
787
        return osutils.pathjoin(base, ".bazaar")
996
792
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
997
793
 
998
794
 
 
795
def branches_config_filename():
 
796
    """Return per-user configuration ini file filename."""
 
797
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
798
 
 
799
 
999
800
def locations_config_filename():
1000
801
    """Return per-user configuration ini file filename."""
1001
802
    return osutils.pathjoin(config_dir(), 'locations.conf')
1011
812
    return osutils.pathjoin(config_dir(), 'ignore')
1012
813
 
1013
814
 
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.
 
815
def _auto_user_id():
 
816
    """Calculate automatic user identification.
 
817
 
 
818
    Returns (realname, email).
 
819
 
 
820
    Only used when none is set in the environment or the id file.
 
821
 
 
822
    This previously used the FQDN as the default domain, but that can
 
823
    be very slow on machines where DNS is broken.  So now we simply
 
824
    use the hostname.
1022
825
    """
 
826
    import socket
 
827
 
1023
828
    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')
 
829
        name = win32utils.get_user_name_unicode()
 
830
        if name is None:
 
831
            raise errors.BzrError("Cannot autodetect user name.\n"
 
832
                                  "Please, set your name with command like:\n"
 
833
                                  'bzr whoami "Your Name <name@domain.com>"')
 
834
        host = win32utils.get_host_name_unicode()
 
835
        if host is None:
 
836
            host = socket.gethostname()
 
837
        return name, (name + '@' + host)
 
838
 
 
839
    try:
 
840
        import pwd
 
841
        uid = os.getuid()
 
842
        try:
 
843
            w = pwd.getpwuid(uid)
 
844
        except KeyError:
 
845
            raise errors.BzrCommandError('Unable to determine your name.  '
 
846
                'Please use "bzr whoami" to set it.')
 
847
 
 
848
        # we try utf-8 first, because on many variants (like Linux),
 
849
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
850
        # false positives.  (many users will have their user encoding set to
 
851
        # latin-1, which cannot raise UnicodeError.)
 
852
        try:
 
853
            gecos = w.pw_gecos.decode('utf-8')
 
854
            encoding = 'utf-8'
 
855
        except UnicodeError:
 
856
            try:
 
857
                encoding = osutils.get_user_encoding()
 
858
                gecos = w.pw_gecos.decode(encoding)
 
859
            except UnicodeError:
 
860
                raise errors.BzrCommandError('Unable to determine your name.  '
 
861
                   'Use "bzr whoami" to set it.')
 
862
        try:
 
863
            username = w.pw_name.decode(encoding)
 
864
        except UnicodeError:
 
865
            raise errors.BzrCommandError('Unable to determine your name.  '
 
866
                'Use "bzr whoami" to set it.')
 
867
 
 
868
        comma = gecos.find(',')
 
869
        if comma == -1:
 
870
            realname = gecos
 
871
        else:
 
872
            realname = gecos[:comma]
 
873
        if not realname:
 
874
            realname = username
 
875
 
 
876
    except ImportError:
 
877
        import getpass
 
878
        try:
 
879
            user_encoding = osutils.get_user_encoding()
 
880
            realname = username = getpass.getuser().decode(user_encoding)
 
881
        except UnicodeDecodeError:
 
882
            raise errors.BzrError("Can't decode username as %s." % \
 
883
                    user_encoding)
 
884
 
 
885
    return realname, (username + '@' + socket.gethostname())
1039
886
 
1040
887
 
1041
888
def parse_username(username):
1129
976
        """Save the config file, only tests should use it for now."""
1130
977
        conf_dir = os.path.dirname(self._filename)
1131
978
        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()
 
979
        self._get_config().write(file(self._filename, 'wb'))
1137
980
 
1138
981
    def _set_option(self, section_name, option_name, value):
1139
982
        """Set an authentication configuration option"""
1487
1330
 
1488
1331
 
1489
1332
class PlainTextCredentialStore(CredentialStore):
1490
 
    __doc__ = """Plain text credential store for the authentication.conf file"""
 
1333
    """Plain text credential store for the authentication.conf file."""
1491
1334
 
1492
1335
    def decode_password(self, credentials):
1493
1336
        """See CredentialStore.decode_password."""
1582
1425
 
1583
1426
    def _get_config_file(self):
1584
1427
        try:
1585
 
            return StringIO(self._transport.get_bytes(self._filename))
 
1428
            return self._transport.get(self._filename)
1586
1429
        except errors.NoSuchFile:
1587
1430
            return StringIO()
1588
1431
 
1589
1432
    def _get_configobj(self):
1590
 
        f = self._get_config_file()
1591
 
        try:
1592
 
            return ConfigObj(f, encoding='utf-8')
1593
 
        finally:
1594
 
            f.close()
 
1433
        return ConfigObj(self._get_config_file(), encoding='utf-8')
1595
1434
 
1596
1435
    def _set_configobj(self, configobj):
1597
1436
        out_file = StringIO()