~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: John Arbash Meinel
  • Date: 2009-03-27 22:29:55 UTC
  • mto: (3735.39.2 clean)
  • mto: This revision was merged to the branch mainline in revision 4280.
  • Revision ID: john@arbash-meinel.com-20090327222955-utifmfm888zerixt
Implement apply_delta_to_source which doesn't have to malloc another string.

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')
923
709
                        trace.warning('Value "%s" is masked by "%s" from'
924
710
                                      ' branch.conf', value, mask_value)
925
711
 
 
712
 
926
713
    def _gpg_signing_command(self):
927
714
        """See Config.gpg_signing_command."""
928
715
        return self._get_safe_value('_gpg_signing_command')
929
716
 
 
717
    def __init__(self, branch):
 
718
        super(BranchConfig, self).__init__()
 
719
        self._location_config = None
 
720
        self._branch_data_config = None
 
721
        self._global_config = None
 
722
        self.branch = branch
 
723
        self.option_sources = (self._get_location_config,
 
724
                               self._get_branch_data_config,
 
725
                               self._get_global_config)
 
726
 
930
727
    def _post_commit(self):
931
728
        """See Config.post_commit."""
932
729
        return self._get_safe_value('_post_commit')
965
762
            os.mkdir(parent_dir)
966
763
        trace.mutter('creating config directory: %r', path)
967
764
        os.mkdir(path)
968
 
        osutils.copy_ownership_from_path(path)
969
765
 
970
766
 
971
767
def config_dir():
986
782
                                  ' or HOME set')
987
783
        return osutils.pathjoin(base, 'bazaar', '2.0')
988
784
    else:
 
785
        # cygwin, linux, and darwin all have a $HOME directory
989
786
        if base is None:
990
787
            base = os.path.expanduser("~")
991
788
        return osutils.pathjoin(base, ".bazaar")
996
793
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
997
794
 
998
795
 
 
796
def branches_config_filename():
 
797
    """Return per-user configuration ini file filename."""
 
798
    return osutils.pathjoin(config_dir(), 'branches.conf')
 
799
 
 
800
 
999
801
def locations_config_filename():
1000
802
    """Return per-user configuration ini file filename."""
1001
803
    return osutils.pathjoin(config_dir(), 'locations.conf')
1011
813
    return osutils.pathjoin(config_dir(), 'ignore')
1012
814
 
1013
815
 
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.
 
816
def _auto_user_id():
 
817
    """Calculate automatic user identification.
 
818
 
 
819
    Returns (realname, email).
 
820
 
 
821
    Only used when none is set in the environment or the id file.
 
822
 
 
823
    This previously used the FQDN as the default domain, but that can
 
824
    be very slow on machines where DNS is broken.  So now we simply
 
825
    use the hostname.
1022
826
    """
 
827
    import socket
 
828
 
1023
829
    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')
 
830
        name = win32utils.get_user_name_unicode()
 
831
        if name is None:
 
832
            raise errors.BzrError("Cannot autodetect user name.\n"
 
833
                                  "Please, set your name with command like:\n"
 
834
                                  'bzr whoami "Your Name <name@domain.com>"')
 
835
        host = win32utils.get_host_name_unicode()
 
836
        if host is None:
 
837
            host = socket.gethostname()
 
838
        return name, (name + '@' + host)
 
839
 
 
840
    try:
 
841
        import pwd
 
842
        uid = os.getuid()
 
843
        try:
 
844
            w = pwd.getpwuid(uid)
 
845
        except KeyError:
 
846
            raise errors.BzrCommandError('Unable to determine your name.  '
 
847
                'Please use "bzr whoami" to set it.')
 
848
 
 
849
        # we try utf-8 first, because on many variants (like Linux),
 
850
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
851
        # false positives.  (many users will have their user encoding set to
 
852
        # latin-1, which cannot raise UnicodeError.)
 
853
        try:
 
854
            gecos = w.pw_gecos.decode('utf-8')
 
855
            encoding = 'utf-8'
 
856
        except UnicodeError:
 
857
            try:
 
858
                encoding = osutils.get_user_encoding()
 
859
                gecos = w.pw_gecos.decode(encoding)
 
860
            except UnicodeError:
 
861
                raise errors.BzrCommandError('Unable to determine your name.  '
 
862
                   'Use "bzr whoami" to set it.')
 
863
        try:
 
864
            username = w.pw_name.decode(encoding)
 
865
        except UnicodeError:
 
866
            raise errors.BzrCommandError('Unable to determine your name.  '
 
867
                'Use "bzr whoami" to set it.')
 
868
 
 
869
        comma = gecos.find(',')
 
870
        if comma == -1:
 
871
            realname = gecos
 
872
        else:
 
873
            realname = gecos[:comma]
 
874
        if not realname:
 
875
            realname = username
 
876
 
 
877
    except ImportError:
 
878
        import getpass
 
879
        try:
 
880
            user_encoding = osutils.get_user_encoding()
 
881
            realname = username = getpass.getuser().decode(user_encoding)
 
882
        except UnicodeDecodeError:
 
883
            raise errors.BzrError("Can't decode username as %s." % \
 
884
                    user_encoding)
 
885
 
 
886
    return realname, (username + '@' + socket.gethostname())
1039
887
 
1040
888
 
1041
889
def parse_username(username):
1069
917
    # XXX: Really needs a better name, as this is not part of the tree! -- mbp 20080507
1070
918
 
1071
919
    def __init__(self, branch):
1072
 
        self._config = branch._get_config()
 
920
        # XXX: Really this should be asking the branch for its configuration
 
921
        # data, rather than relying on a Transport, so that it can work
 
922
        # more cleanly with a RemoteBranch that has no transport.
 
923
        self._config = TransportConfig(branch._transport, 'branch.conf')
1073
924
        self.branch = branch
1074
925
 
1075
926
    def _get_parser(self, file=None):
1083
934
            return self._config.get_option(name, section, default)
1084
935
        finally:
1085
936
            self.branch.unlock()
 
937
        return result
1086
938
 
1087
939
    def set_option(self, value, name, section=None):
1088
940
        """Set a per-branch configuration option"""
1129
981
        """Save the config file, only tests should use it for now."""
1130
982
        conf_dir = os.path.dirname(self._filename)
1131
983
        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()
 
984
        self._get_config().write(file(self._filename, 'wb'))
1137
985
 
1138
986
    def _set_option(self, section_name, option_name, value):
1139
987
        """Set an authentication configuration option"""
1235
1083
                trace.mutter("Using authentication section: %r", auth_def_name)
1236
1084
            break
1237
1085
 
1238
 
        if credentials is None:
1239
 
            # No credentials were found in authentication.conf, try the fallback
1240
 
            # credentials stores.
1241
 
            credentials = credential_store_registry.get_fallback_credentials(
1242
 
                scheme, host, port, user, path, realm)
1243
 
 
1244
1086
        return credentials
1245
1087
 
1246
1088
    def set_credentials(self, name, host, user, scheme=None, password=None,
1288
1130
        config.update({name: values})
1289
1131
        self._save()
1290
1132
 
1291
 
    def get_user(self, scheme, host, port=None, realm=None, path=None,
1292
 
                 prompt=None, ask=False, default=None):
 
1133
    def get_user(self, scheme, host, port=None,
 
1134
                 realm=None, path=None, prompt=None):
1293
1135
        """Get a user from authentication file.
1294
1136
 
1295
1137
        :param scheme: protocol
1302
1144
 
1303
1145
        :param path: the absolute path on the server (optional)
1304
1146
 
1305
 
        :param ask: Ask the user if there is no explicitly configured username 
1306
 
                    (optional)
1307
 
 
1308
 
        :param default: The username returned if none is defined (optional).
1309
 
 
1310
1147
        :return: The found user.
1311
1148
        """
1312
1149
        credentials = self.get_credentials(scheme, host, port, user=None,
1315
1152
            user = credentials['user']
1316
1153
        else:
1317
1154
            user = None
1318
 
        if user is None:
1319
 
            if ask:
1320
 
                if prompt is None:
1321
 
                    # Create a default prompt suitable for most cases
1322
 
                    prompt = scheme.upper() + ' %(host)s username'
1323
 
                # Special handling for optional fields in the prompt
1324
 
                if port is not None:
1325
 
                    prompt_host = '%s:%d' % (host, port)
1326
 
                else:
1327
 
                    prompt_host = host
1328
 
                user = ui.ui_factory.get_username(prompt, host=prompt_host)
1329
 
            else:
1330
 
                user = default
1331
1155
        return user
1332
1156
 
1333
1157
    def get_password(self, scheme, host, user, port=None,
1388
1212
    A credential store provides access to credentials via the password_encoding
1389
1213
    field in authentication.conf sections.
1390
1214
 
1391
 
    Except for stores provided by bzr itself, most stores are expected to be
 
1215
    Except for stores provided by bzr itself,most stores are expected to be
1392
1216
    provided by plugins that will therefore use
1393
1217
    register_lazy(password_encoding, module_name, member_name, help=help,
1394
 
    fallback=fallback) to install themselves.
1395
 
 
1396
 
    A fallback credential store is one that is queried if no credentials can be
1397
 
    found via authentication.conf.
 
1218
    info=info) to install themselves.
1398
1219
    """
1399
1220
 
1400
1221
    def get_credential_store(self, encoding=None):
1403
1224
            cs = cs()
1404
1225
        return cs
1405
1226
 
1406
 
    def is_fallback(self, name):
1407
 
        """Check if the named credentials store should be used as fallback."""
1408
 
        return self.get_info(name)
1409
 
 
1410
 
    def get_fallback_credentials(self, scheme, host, port=None, user=None,
1411
 
                                 path=None, realm=None):
1412
 
        """Request credentials from all fallback credentials stores.
1413
 
 
1414
 
        The first credentials store that can provide credentials wins.
1415
 
        """
1416
 
        credentials = None
1417
 
        for name in self.keys():
1418
 
            if not self.is_fallback(name):
1419
 
                continue
1420
 
            cs = self.get_credential_store(name)
1421
 
            credentials = cs.get_credentials(scheme, host, port, user,
1422
 
                                             path, realm)
1423
 
            if credentials is not None:
1424
 
                # We found some credentials
1425
 
                break
1426
 
        return credentials
1427
 
 
1428
 
    def register(self, key, obj, help=None, override_existing=False,
1429
 
                 fallback=False):
1430
 
        """Register a new object to a name.
1431
 
 
1432
 
        :param key: This is the key to use to request the object later.
1433
 
        :param obj: The object to register.
1434
 
        :param help: Help text for this entry. This may be a string or
1435
 
                a callable. If it is a callable, it should take two
1436
 
                parameters (registry, key): this registry and the key that
1437
 
                the help was registered under.
1438
 
        :param override_existing: Raise KeyErorr if False and something has
1439
 
                already been registered for that key. If True, ignore if there
1440
 
                is an existing key (always register the new value).
1441
 
        :param fallback: Whether this credential store should be 
1442
 
                used as fallback.
1443
 
        """
1444
 
        return super(CredentialStoreRegistry,
1445
 
                     self).register(key, obj, help, info=fallback,
1446
 
                                    override_existing=override_existing)
1447
 
 
1448
 
    def register_lazy(self, key, module_name, member_name,
1449
 
                      help=None, override_existing=False,
1450
 
                      fallback=False):
1451
 
        """Register a new credential store to be loaded on request.
1452
 
 
1453
 
        :param module_name: The python path to the module. Such as 'os.path'.
1454
 
        :param member_name: The member of the module to return.  If empty or
1455
 
                None, get() will return the module itself.
1456
 
        :param help: Help text for this entry. This may be a string or
1457
 
                a callable.
1458
 
        :param override_existing: If True, replace the existing object
1459
 
                with the new one. If False, if there is already something
1460
 
                registered with the same key, raise a KeyError
1461
 
        :param fallback: Whether this credential store should be 
1462
 
                used as fallback.
1463
 
        """
1464
 
        return super(CredentialStoreRegistry, self).register_lazy(
1465
 
            key, module_name, member_name, help,
1466
 
            info=fallback, override_existing=override_existing)
1467
 
 
1468
1227
 
1469
1228
credential_store_registry = CredentialStoreRegistry()
1470
1229
 
1473
1232
    """An abstract class to implement storage for credentials"""
1474
1233
 
1475
1234
    def decode_password(self, credentials):
1476
 
        """Returns a clear text password for the provided credentials."""
 
1235
        """Returns a password for the provided credentials in clear text."""
1477
1236
        raise NotImplementedError(self.decode_password)
1478
1237
 
1479
 
    def get_credentials(self, scheme, host, port=None, user=None, path=None,
1480
 
                        realm=None):
1481
 
        """Return the matching credentials from this credential store.
1482
 
 
1483
 
        This method is only called on fallback credential stores.
1484
 
        """
1485
 
        raise NotImplementedError(self.get_credentials)
1486
 
 
1487
 
 
1488
1238
 
1489
1239
class PlainTextCredentialStore(CredentialStore):
1490
 
    __doc__ = """Plain text credential store for the authentication.conf file"""
 
1240
    """Plain text credential store for the authentication.conf file."""
1491
1241
 
1492
1242
    def decode_password(self, credentials):
1493
1243
        """See CredentialStore.decode_password."""
1501
1251
 
1502
1252
class BzrDirConfig(object):
1503
1253
 
1504
 
    def __init__(self, bzrdir):
1505
 
        self._bzrdir = bzrdir
1506
 
        self._config = bzrdir._get_config()
 
1254
    def __init__(self, transport):
 
1255
        self._config = TransportConfig(transport, 'control.conf')
1507
1256
 
1508
1257
    def set_default_stack_on(self, value):
1509
1258
        """Set the default stacking location.
1513
1262
        This policy affects all branches contained by this bzrdir, except for
1514
1263
        those under repositories.
1515
1264
        """
1516
 
        if self._config is None:
1517
 
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
1518
1265
        if value is None:
1519
1266
            self._config.set_option('', 'default_stack_on')
1520
1267
        else:
1528
1275
        This policy affects all branches contained by this bzrdir, except for
1529
1276
        those under repositories.
1530
1277
        """
1531
 
        if self._config is None:
1532
 
            return None
1533
1278
        value = self._config.get_option('default_stack_on')
1534
1279
        if value == '':
1535
1280
            value = None
1580
1325
            configobj.setdefault(section, {})[name] = value
1581
1326
        self._set_configobj(configobj)
1582
1327
 
1583
 
    def _get_config_file(self):
 
1328
    def _get_configobj(self):
1584
1329
        try:
1585
 
            return StringIO(self._transport.get_bytes(self._filename))
 
1330
            return ConfigObj(self._transport.get(self._filename),
 
1331
                             encoding='utf-8')
1586
1332
        except errors.NoSuchFile:
1587
 
            return StringIO()
1588
 
 
1589
 
    def _get_configobj(self):
1590
 
        f = self._get_config_file()
1591
 
        try:
1592
 
            return ConfigObj(f, encoding='utf-8')
1593
 
        finally:
1594
 
            f.close()
 
1333
            return ConfigObj(encoding='utf-8')
1595
1334
 
1596
1335
    def _set_configobj(self, configobj):
1597
1336
        out_file = StringIO()